Compare commits

...

348 Commits
5.4.2 ... 5.6

Author SHA1 Message Date
Mario
3a2e5d480c update include/items.php 2021-05-11 12:14:44 +00:00
Mario
26e851ff7f Merge branch '5.6RC' 2021-05-11 11:59:49 +00:00
Mario
89ec043ce1 version 5.6 2021-05-11 11:58:16 +00:00
Mario
98f0272a84 Merge branch '5.6RC' of https://framagit.org/hubzilla/core into 5.6RC 2021-05-11 11:57:22 +00:00
Mario
0933925a2b Merge branch 'dev' into 5.6RC 2021-05-11 11:57:13 +00:00
Mario
e92929fce4 changelog 2021-05-11 11:56:54 +00:00
Mario
f388412c48 id should be intval here
(cherry picked from commit 836de7f1a5)
2021-05-10 09:07:59 +00:00
Mario
836de7f1a5 id should be intval here 2021-05-10 09:05:27 +00:00
Mario
43008aa42b Merge branch '5.6RC' of https://framagit.org/hubzilla/core into 5.6RC 2021-05-08 08:44:29 +00:00
Mario
7618d8301a 5.6RC3 2021-05-08 08:44:13 +00:00
Mario
09cfc979e4 Merge branch 'dev' into 5.6RC 2021-05-08 08:43:00 +00:00
Mario
00fc5541db remove redundant placeholder in query
(cherry picked from commit 954d06bdb7)
2021-05-08 08:29:56 +00:00
Mario
954d06bdb7 remove redundant placeholder in query 2021-05-08 08:29:04 +00:00
Mario
12828ee4d4 update 1245 to fix hubloc_hash index for postgres
(cherry picked from commit c2e007a839)
2021-05-07 18:47:06 +00:00
Mario
c2e007a839 update 1245 to fix hubloc_hash index for postgres 2021-05-07 15:02:55 +00:00
Mario
605bf3b9d3 register: postgres - add default values for timestamps
(cherry picked from commit ebd0333256)
2021-05-07 12:15:56 +00:00
Mario
ebd0333256 register: postgres - add default values for timestamps 2021-05-07 12:15:00 +00:00
Mario
d7dcf192c7 remove logging
(cherry picked from commit 2ad6f6e11f)
2021-05-07 11:09:09 +00:00
Mario
2ad6f6e11f remove logging 2021-05-07 11:08:40 +00:00
Mario
36a814b03e version 5.6RC2 2021-05-07 11:03:59 +00:00
Mario
92bc99a805 strings 2021-05-07 11:02:21 +00:00
Mario
b5ce207344 register: implement remove_expired_registrations() and minor fixes 2021-05-07 10:03:12 +00:00
Mario
d04ff264fa register: fix minor string issue 2021-05-07 08:26:59 +00:00
Mario
9ad2b017e2 register: fix language issue and add additional info to the infobox if email verification is configured 2021-05-07 08:15:06 +00:00
Mario
1fd5f5c893 register: redirect unverified registration emails to the verification form 2021-05-06 19:06:53 +00:00
Mario
43260891b7 register: we have already checked for existing email in check_account_email() 2021-05-06 13:54:02 +00:00
Mario
aef0350346 remove duplicate singletons hublocs once a day 2021-05-05 09:15:02 +00:00
Mario
83fbb0678c use hubloc_hash instead of hubloc_id_url - otherwise it will bite hublocs which use more than one protocol 2021-05-05 08:50:03 +00:00
Mario
df3778c64f Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-05-05 08:36:43 +00:00
Mario
0dc09ea238 possible minor performance improvement 2021-05-05 08:36:18 +00:00
Max Kostikov
f085c3c98f Merge branch 'translation-pl' into 'dev'
Fixes related to correction plural expression, plus typos and some other

See merge request hubzilla/core!1950
2021-05-02 12:17:13 +00:00
Mario
8d4b1ba7d4 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-05-02 11:33:45 +00:00
Mario
b3c543265d introduce function to remove duplicate singleton hublocs 2021-05-02 11:33:26 +00:00
Andrzej Budziński
6eee404bb1 Fixes related to correction plural expression, plus typos and some other
fixes
2021-05-01 02:43:17 +02:00
Max Kostikov
ec4226b5de Merge branch 'dev' into 'dev'
Fix Polish plurals expression

See merge request hubzilla/core!1949
2021-04-30 19:28:15 +00:00
Max Kostikov
8266a1490a Fix Polish plurals expression 2021-04-30 21:24:44 +02:00
Max Kostikov
56554710ea Merge branch 'dev' into 'dev'
Dev sync

See merge request kostikov/core!2
2021-04-30 19:23:26 +00:00
Max Kostikov
6a101e6260 Merge branch 'translation-pl' into 'dev'
Translation update to v.5.7 plus fixes and typos

See merge request hubzilla/core!1948
2021-04-30 18:34:29 +00:00
Andrzej Budziński
f12038e63e Translation update to v.5.7 plus fixes and typos 2021-04-30 12:54:22 +02:00
Max Kostikov
ad2bf187bb Merge branch 'dev' into 'dev'
Update Russian translation; fix missprint

See merge request hubzilla/core!1947
2021-04-29 10:10:27 +00:00
Max Kostikov
4cbd97e409 Update Russian translation 2021-04-29 12:06:53 +02:00
Max Kostikov
e67c780afd Fix missprint 2021-04-29 11:35:14 +02:00
Max Kostikov
0cbdeb7bf1 Merge branch 'dev' into 'dev'
Dev Sync

See merge request kostikov/core!1
2021-04-29 09:32:02 +00:00
Mario
6be464ef84 bump version 2021-04-29 08:40:47 +00:00
Mario
54845a7627 composer dump autoload 2021-04-29 08:33:58 +00:00
Mario
2f6da0be7e version and strings 2021-04-29 08:30:31 +00:00
Mario
cf87a5af3b fix typos in Activity::follow() 2021-04-29 07:35:22 +00:00
Mario
207057c92d Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-04-29 06:47:26 +00:00
Mario
5300f180db really fix manual fetching of non-ascii domains 2021-04-29 06:47:03 +00:00
Mario
ec7166eb00 fix manual fetching of non-ascii domains 2021-04-28 19:38:43 +02:00
Mario
36f041a1ff cleanup 2021-04-28 14:23:53 +02:00
Mario
0dd2e9004d do not attempt to translate twice 2021-04-28 13:21:49 +02:00
Mario
94f1c001f1 register: more testing and fixes 2021-04-28 13:17:45 +02:00
Mario
531a03562d register: new install testing fixes 2021-04-27 15:09:27 +02:00
Mario
3699f78e95 register: remove single quotes in advanced examples - they might be misleading 2021-04-27 08:08:21 +00:00
Mario
ebd2283b38 more strings changes 2021-04-26 20:33:16 +00:00
Mario
a7788570e5 register: remove debug messages from UI and streamline some strings 2021-04-26 20:30:38 +00:00
Mario
2932ac9d86 register: only log to separate file if configured that way. default to standard logging via logger() 2021-04-26 18:31:08 +00:00
Mario
888c211f44 check perms for comments since in AP they can be different from the top level post 2021-04-26 11:53:25 +00:00
Max Kostikov
61cf92ebdd Support new parse_str() syntax 2021-04-24 22:23:50 +00:00
Mario
80ec45e4f9 fix variable mixup 2021-04-22 19:48:59 +00:00
Mario
9e9851681f Merge branch 'dev' into 'dev'
Fix clones sync when wiki or single wiki page deletion

See merge request hubzilla/core!1945
2021-04-22 17:53:47 +00:00
Max Kostikov
8394d4857c Fix clones sync when wiki or single wiki page deletion 2021-04-22 17:53:47 +00:00
Mario
c700a017a0 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-04-22 17:43:26 +00:00
Mario
c19eb94c52 make sure we transform events to UTC on import before storing. Transform from event timezone if available otherwise channel default 2021-04-22 17:42:58 +00:00
Mario Vavti
597f24ca49 invite: fix javascript issue 2021-04-22 10:07:17 +02:00
Mario
eb793b1601 bump version 2021-04-21 19:28:41 +00:00
Mario
07525c5b45 next batch of fixes 2021-04-21 18:51:53 +00:00
Mario
35df50c39d start sending author id, id_sig and key fields along with author/owner and adjust import_author_xchan() accordingly 2021-04-21 07:55:35 +00:00
Mario Vavti
406ca20634 version 5.4.3 2021-04-20 11:13:19 +02:00
Mario
021e7861b8 changelog
(cherry picked from commit 5dfe4ef6f8)
2021-04-20 11:12:13 +02:00
Mario
5dfe4ef6f8 changelog 2021-04-20 09:11:45 +00:00
Mario
60a0fdc76b fix regression in mod notifications
(cherry picked from commit b8a5f5fbf2)
2021-04-20 10:58:56 +02:00
Mario
cd760454a5 floc off google
(cherry picked from commit 7ccd7b439f)
2021-04-20 10:58:38 +02:00
Mario
c7144dbf96 use protect_sprintf() on query strings
(cherry picked from commit f9793e870f)
2021-04-20 10:57:36 +02:00
Miłosz Kłosowicz
c31e203104 Wfinger - check https from http_x_forwarded_proto
(cherry picked from commit aa2450fae1)
2021-04-20 10:57:00 +02:00
Mario
6feefc5ce0 fix regression finding bookmarks
(cherry picked from commit 16cc695115)
2021-04-20 10:56:37 +02:00
Mario
1d7f9e05ed Merge branch 'dev' into 'dev'
more PHP 8 fixes

See merge request hubzilla/core!1943
2021-04-20 08:53:32 +00:00
Mario
6a858b29fd potential export issue when using PHP8
(cherry picked from commit ba412bc6cf)
2021-04-20 10:52:39 +02:00
Mario
3f0e687558 if we use dbescbin on save we should use dbunescbin when retrieving (at least that is true for postgres)
(cherry picked from commit 31abcac4b4)
2021-04-20 10:52:18 +02:00
Mario
ba412bc6cf potential export issue when using PHP8 2021-04-20 08:49:03 +00:00
Mario
31abcac4b4 if we use dbescbin on save we should use dbunescbin when retrieving (at least that is true for postgres) 2021-04-20 08:42:58 +00:00
Mario
d7f04ff6ee when importing a channel, make sure we import the xchan before the hubloc - otherwise we can not verify the hubloc hash
(cherry picked from commit eaf9003ca2)
2021-04-20 10:36:08 +02:00
Mario
76fd81fad1 revert last part of previous commit -> see comment above the change
(cherry picked from commit eded0f6c09)
2021-04-20 10:35:27 +02:00
Mario
1cfcffc510 import_items(): make sure we compare the correct revision and only call item_store_update() if edited timestamp of the received item > stored item timestamp
(cherry picked from commit c95a6fe1e5)
2021-04-20 10:35:11 +02:00
Mario
eaf9003ca2 when importing a channel, make sure we import the xchan before the hubloc - otherwise we can not verify the hubloc hash 2021-04-20 08:09:33 +00:00
Mario
751d6fe8a4 register: minor strings changes and whitespace 2021-04-19 19:29:35 +00:00
Mario
20ca6676d2 registration: reveal possibility to show all registrations in the UI 2021-04-19 19:07:50 +00:00
Mario
eded0f6c09 revert last part of previous commit -> see comment above the change 2021-04-19 10:49:41 +00:00
Mario
b5049651ad Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-04-19 10:41:51 +00:00
Mario
c95a6fe1e5 import_items(): make sure we compare the correct revision and only call item_store_update() if edited timestamp of the received item > stored item timestamp 2021-04-19 10:41:28 +00:00
Max Kostikov
cd97c32444 more PHP 8 fixes 2021-04-18 21:25:32 +02:00
Max Kostikov
70b204cb3f Merge branch 'dev' into 'dev'
PHP 8 fixes

See merge request hubzilla/core!1942
2021-04-18 07:29:41 +00:00
Max Kostikov
d2f1edfad8 PHP 8 fixes 2021-04-18 09:27:25 +02:00
Max Kostikov
2ddfcd5222 PHP 8 fixes 2021-04-18 09:23:14 +02:00
Max Kostikov
787ee411ce PHP 8 fixes 2021-04-17 23:50:19 +02:00
Max Kostikov
200d3577fa Merge branch 'dev' of https://framagit.org/kostikov/core into dev 2021-04-17 23:46:40 +02:00
Max Kostikov
8ab99747f5 Merge branch 'translation-pl' into 'dev'
Next fixes and typos, and new docs translations

See merge request hubzilla/core!1941
2021-04-16 19:31:44 +00:00
Mario
88f7c2041d register: add option to show all register entries 2021-04-16 18:13:20 +00:00
Andrzej Budziński
43cb21329f Next fixes and typos, and new docs translatons 2021-04-16 16:30:03 +02:00
Mario
b8a5f5fbf2 fix regression in mod notifications 2021-04-16 12:41:31 +00:00
Mario
7ccd7b439f floc off google 2021-04-16 09:14:40 +00:00
Mario
f0eceb03ed prepare Activity::follow() for pubcrawl 2021-04-16 08:08:15 +00:00
Mario
c2b9fc1a49 register: add help text to the message field 2021-04-15 13:10:20 +00:00
Mario
4d3a555b53 register: minor fixes and template cleanup 2021-04-15 09:26:47 +00:00
Mario
e35ab97b7e register: provide a possibility to leave a message id registration is by approval 2021-04-14 19:40:51 +00:00
Mario
f9793e870f use protect_sprintf() on query strings 2021-04-14 11:01:34 +00:00
Mario
e48fedd526 most AP projects do not handle an array for person object URL - provide a string 2021-04-14 09:30:19 +00:00
Mario
b899ed3d64 register: change some strings and add new template 2021-04-13 13:04:43 +00:00
Mario
e4adb881cb Merge branch 'dev' into 'dev'
Wfinger - check https from http_x_forwarded_proto

See merge request hubzilla/core!1940
2021-04-12 18:52:37 +00:00
Miłosz Kłosowicz
aa2450fae1 Wfinger - check https from http_x_forwarded_proto 2021-04-12 10:33:21 +00:00
Mario
d9245566f5 register: change some strings and some whitespace fixes 2021-04-11 17:46:06 +00:00
Mario
16cc695115 fix regression finding bookmarks 2021-04-11 15:47:42 +00:00
Mario
f0e5ce7fd1 register: more work on ui/ux 2021-04-10 20:44:04 +00:00
Mario
ea721d380b register: move some html out of the code and provide a basic template 2021-04-10 10:53:27 +00:00
Mario
e193b6d870 feature level is deprecated 2021-04-10 08:00:03 +00:00
Mario
766fc92a3b register: we use default role if auto create is configured 2021-04-09 19:25:31 +00:00
Mario
df6f2abfbe register: if auto create is configured do some more tests against the provided name and nick so it will not fail later in create_identity(); 2021-04-09 19:06:36 +00:00
Mario
684245f24d whitespace 2021-04-09 09:57:22 +00:00
Mario
01b081d809 register: only return verified registrations in get_pending_accounts(), more invite handling fixes 2021-04-09 09:49:36 +00:00
Mario
a34d8852b6 minor revert 2021-04-08 20:01:56 +00:00
Mario
18b6d48944 rgister: fixes for registering with invitecode outside of open hours 2021-04-08 19:55:53 +00:00
Mario
f3fa09fc91 register: more ui/ux 2021-04-08 16:06:43 +00:00
Mario
cb2d8b4ba6 register: minor js cleanup 2021-04-08 15:03:05 +00:00
Mario
a9da370c0b register: cleanup template 2021-04-08 14:57:16 +00:00
Max Kostikov
b5620cb794 Merge branch 'dev' into 'dev'
Dev sync

See merge request kostikov/core!1
2021-04-08 14:19:29 +00:00
Mario
cf62e07bec register: default to auto-create channel and fix auto create channel if register approval is configured 2021-04-08 12:38:38 +00:00
Mario
ec4526b5f4 cloud: instead of asking for a page reload when expiriencing a not implemnented exception just go there right away - issue #1556 2021-04-08 08:25:35 +00:00
Mario
806f50eee3 register: more ui/ux work 2021-04-07 20:50:34 +02:00
Mario
6956eadaad registrations: minor cleanup 2021-04-07 17:19:29 +02:00
Mario
9542c1d63c Merge branch 'dev' into 'dev'
air: Fix site admin registration block styles

See merge request hubzilla/core!1938
2021-04-07 14:12:01 +00:00
Mario
81bb02afb7 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-04-06 12:13:24 +00:00
Mario
b8abf806ca bbcode: escape img and zmg tags so that it will not be messed with before required (e.g. URL in image description) - issue #1554 2021-04-06 12:12:51 +00:00
Max Kostikov
0d10f5ba65 Fix site admin registration block styles 2021-04-06 13:41:33 +02:00
Max Kostikov
89409d0577 Merge branch 'dev' into 'dev'
Fix quotes Russian translation

See merge request hubzilla/core!1937
2021-04-06 11:21:10 +00:00
Max Kostikov
144283ca1c Fix quotes 2021-04-06 11:16:47 +00:00
Max Kostikov
c56e2953cf Fix quotes 2021-04-06 11:16:25 +00:00
Max Kostikov
e1d40348ce Update hstrings.php 2021-04-06 11:09:48 +00:00
Max Kostikov
4def370980 Merge branch 'dev' into 'dev'
Update Russian translation

See merge request hubzilla/core!1936
2021-04-06 11:00:14 +00:00
Max Kostikov
54df52675b Revert "Fix mistake"
This reverts commit 9ac5504377
2021-04-06 12:30:03 +02:00
Max Kostikov
12ebdf27c0 Fix variables 2021-04-06 10:27:19 +00:00
Max Kostikov
de0f7ea5d4 Update register_verify_member.tpl 2021-04-06 10:26:26 +00:00
Max Kostikov
72151bc123 Add new file 2021-04-06 10:21:32 +00:00
Max Kostikov
8889abd5a4 Add new file 2021-04-06 10:20:50 +00:00
Max Kostikov
7f7dcd2f33 Fix missprint 2021-04-06 10:18:12 +00:00
Max Kostikov
95c3b1696e Add new formal invitation subject 2021-04-06 10:17:46 +00:00
Max Kostikov
87cd1f87f4 Add formal invitation 2021-04-06 10:16:22 +00:00
Max Kostikov
21c4976a3a Add new invitation subject 2021-04-06 09:59:40 +00:00
Max Kostikov
ec91e51142 Add friendly invitation 2021-04-06 09:56:11 +00:00
Max Kostikov
f1c798e9ac Update Russian hstrings.php 2021-04-06 09:50:44 +00:00
Max Kostikov
f6996f4999 Update Russian hmessages.po 2021-04-06 09:50:21 +00:00
Max Kostikov
9ac5504377 Fix mistake 2021-04-06 09:33:17 +00:00
Mario
91f3c722d6 bump version 2021-04-06 07:57:35 +00:00
Mario
31cf2c688c Merge branch 'dev' into air 2021-04-06 07:55:30 +00:00
Mario
81d3ba5151 do not expire page cache - it does not make much sense actually. 2021-04-06 07:48:09 +00:00
Max Kostikov
19daadbfd7 Merge branch 'translation-pl' into 'dev'
Upgrading POT, additional translations and next fixes

See merge request hubzilla/core!1935
2021-04-05 20:55:14 +00:00
Andrzej Budziński
0acb371f62 Upgrading POT, additional translations and next fixes 2021-04-05 16:34:30 +02:00
Mario
18d990a034 air: more ui/ux and provide a possibility to lookup your registration id in mod regate (raw and unfinished) 2021-03-28 20:40:26 +00:00
Mario
85b6e352d4 air: fixes 2021-03-28 10:17:54 +00:00
Mario
c389aee112 Merge branch 'air' of https://framagit.org/hubzilla/core into air 2021-03-26 21:04:26 +01:00
Mario
725e57a27a air: more work on UX during register 2021-03-26 20:54:48 +01:00
Mario
9aab47de07 fix timezone issue in mod cal
(cherry picked from commit 6e7c7771bd)
2021-03-26 20:24:51 +01:00
Mario
e6a6723d1f Merge branch 'air' of https://framagit.org/hubzilla/core into air 2021-03-26 19:21:41 +00:00
Mario
6e7c7771bd fix timezone issue in mod cal 2021-03-26 19:20:38 +00:00
Max Kostikov
c609fc71bd Merge branch 'translation-pl' into 'dev'
Fixes and new translations

See merge request hubzilla/core!1934
2021-03-25 19:36:18 +00:00
Mario
b50f1657c3 Merge branch 'air' of https://framagit.org/hubzilla/core into air 2021-03-25 14:00:49 +01:00
Mario
bc1cc65ff2 air: currently it is allowed to register with non-unique did2 (should this be allowed?) - anyway, for now sort them by reg_created to make sure we always match the latest attempt 2021-03-25 14:00:25 +01:00
Andrzej S. Budziński
697e59f9a4 Update hstrings.php 2021-03-25 12:59:45 +00:00
Andrzej Budziński
61d6239c68 Fixes and new translations
1) Changed translations of "a hub" and "a post" ("a hub" like "a node of
network" and not like "a web-hub" or "an air hub".) The word "a post"
should be translated as Polish "wpis" and not jargon "post".
2) New translation: doc/pl/Widgets.md
2021-03-24 23:30:42 +01:00
Mario
eba69f85c7 more work on mod display
(cherry picked from commit 2d716b74b9)
2021-03-24 20:48:42 +01:00
Mario
19b96e37fb Merge branch 'dev' into air 2021-03-24 19:46:07 +00:00
Mario
14186f5c18 cdav: fix regression - sync code was messing with caldav/carddav discovery 2021-03-24 19:41:20 +00:00
Mario
44593a3c8d cdav: fix regression - sync code was messing with caldav/carddav discovery 2021-03-24 19:27:44 +00:00
Mario
4964a32c55 Revalidate imported profile photo on each request (patch provided by Max)
(cherry picked from commit 3d4ad94dcc)
2021-03-24 12:18:32 +01:00
Mario
3d4ad94dcc Revalidate imported profile photo on each request (patch provided by Max) 2021-03-24 11:16:03 +00:00
Mario
6d5f98072d php8: fix fatal errors
(cherry picked from commit 1a15c775f8)
2021-03-24 11:39:19 +01:00
Mario
1a15c775f8 php8: fix fatal errors 2021-03-24 09:21:58 +00:00
Mario
2d716b74b9 more work on mod display 2021-03-23 11:38:42 +00:00
Mario
cc9fd4f4a4 fix regression in mod display
(cherry picked from commit 43c5b72317)
2021-03-23 12:05:40 +01:00
Mario
43c5b72317 fix regression in mod display 2021-03-23 10:54:27 +00:00
Mario
2856ea6370 Merge branch 'dev' into air 2021-03-23 09:56:46 +00:00
Max Kostikov
67d65d878d Merge branch 'dev' into 'dev'
Fix DAV calendars and addressbooks sync on remote access

See merge request hubzilla/core!1931
2021-03-22 14:21:38 +00:00
Max Kostikov
e19bb63857 Merge branch 'translation-pl' into 'dev'
Translation pl

See merge request hubzilla/core!1930
2021-03-22 14:20:56 +00:00
Max Kostikov
dbc5e54a92 Fix DAV calendars and addressbooks sync on remote access 2021-03-22 14:16:54 +00:00
Mario
b8913335b1 those are not actually needed by the handler
(cherry picked from commit 872ac8846e)
2021-03-22 13:51:44 +01:00
Mario
872ac8846e those are not actually needed by the handler 2021-03-22 13:51:11 +01:00
Mario
8c16171855 sse: make sure to also bootstrap info and notice
(cherry picked from commit 598c3aa336)
2021-03-22 13:43:00 +01:00
Mario
2e47ef38a9 libsync fix from zap: look for hubloc_updated instead of hubloc_connected which would always be true
(cherry picked from commit ccefb99cbe)
2021-03-22 13:42:01 +01:00
Mario
81b4d919e5 do not treat an URL including an @ like a webbie
(cherry picked from commit 35ce7dbeab)
2021-03-22 13:41:39 +01:00
Mario
f6d88f20f3 Merge branch 'air' of https://framagit.org/hubzilla/core into air 2021-03-22 13:37:31 +01:00
Mario
598c3aa336 sse: make sure to also bootstrap info and notice 2021-03-22 13:37:01 +01:00
Mario
ccefb99cbe libsync fix from zap: look for hubloc_updated instead of hubloc_connected which would always be true 2021-03-22 10:12:57 +00:00
Mario
35ce7dbeab do not treat an URL including an @ like a webbie 2021-03-22 10:01:32 +00:00
Mario
74610aca6f Merge branch 'air' of https://framagit.org/hubzilla/core into air 2021-03-22 10:29:54 +01:00
Mario
02d4c5ac90 Merge branch 'air' of https://framagit.org/hubzilla/core into air 2021-03-22 09:29:23 +00:00
Mario
7f35dda5cc Merge branch 'dev' into air 2021-03-22 10:28:08 +01:00
Mario
13355d42f7 air security: saving the password as hex string is not acceptable 2021-03-22 09:50:12 +01:00
Andrzej Budziński
77e82d7475 Fixes (Translation.md, hstrings.php) 2021-03-21 19:54:22 +01:00
Andrzej Budziński
da2df4eb55 Fixes and next translations (doc/pl/Plugins.md) 2021-03-21 18:17:06 +01:00
Mario
62fbdf3f63 Merge branch 'air' into 'air'
adminUI cfg to switch on (default off) register w/o email, Issue Air #1539

See merge request hubzilla/core!1927
2021-03-20 16:01:21 +00:00
Mario
554745a25a air: do not require to verify emailaddress once more after invite code got verified - fixes #1546 but probably still requires some finetuning. 2021-03-20 16:57:11 +01:00
Hilmar R
e12c0ca3dc adminUI cfg to switch on (default off) register w/o email,
accept delay 0 (no delay) and expire defaults to 99years
2021-03-19 21:10:01 +01:00
Mario
a18e297a26 Merge branch 'dev' into air 2021-03-19 20:07:59 +00:00
Mario
2d82e1bd6b Merge branch 'dev' into 'dev'
Implement custom Redis session backend

See merge request hubzilla/core!1926
2021-03-19 20:07:00 +00:00
Max Kostikov
7476d8dccc Implement custom Redis session backend 2021-03-19 20:06:59 +00:00
Mario
04b96e2cdc air: php8 asort() argument cannot be passed by reference 2021-03-19 12:06:38 +01:00
Mario
7375824ed4 air: missing module 2021-03-19 11:45:40 +01:00
Mario
06d47deef8 air: improved UX by changing the registration workflow so that it is not required to go back to registration and post the DID. If no registration delay is configured proceed directly to verification. fixes #1540 2021-03-19 11:43:48 +01:00
Mario
85d000e792 air: revert min_livetime of the form security token - it has had its issues and air can be configured for delayed registration verification 2021-03-18 19:51:30 +00:00
Mario
3ac27d8004 air: display the verification status in the notifications 2021-03-18 19:41:12 +00:00
Mario
854a6e3787 air: only set registration request to expired if it is not yet verified 2021-03-18 14:56:53 +00:00
Mario
a36dd5a8b9 adjust timezone after the expiration check 2021-03-18 14:47:37 +00:00
Mario
7c620cbe24 air: make sure to display the timezone corrected times in the admin ui 2021-03-18 14:42:30 +00:00
Mario
7472b96c95 Merge branch 'air' of https://framagit.org/hubzilla/core into air 2021-03-18 14:55:28 +01:00
Mario
3ba42d3dcf air: deal with timezones when displaying open/close time - this should finally fix issue #1544 2021-03-18 14:55:01 +01:00
Mario
eb3a40b07a use lib/keyutils rsatopem()
(cherry picked from commit f0cce1c902)
2021-03-18 09:37:55 +01:00
Mario
f0cce1c902 use lib/keyutils rsatopem() 2021-03-18 08:35:09 +00:00
Mario
9f26b7aa9c air: convert utc to local in browser (we do not have a client timezone othervise at this point) - issue #1544 2021-03-17 17:49:13 +01:00
Mario
febf766be0 air: make sure we always save date_time in UTC - issue #1544 2021-03-17 14:37:16 +01:00
Mario
35d9fd4860 air: another string 2021-03-17 12:24:19 +01:00
Mario
4581abb6d1 air: some work on ui/ux 2021-03-17 12:14:55 +01:00
Mario
8d3c5114ba use html2plain for summary
(cherry picked from commit 80b6954c29)
2021-03-17 10:13:55 +01:00
Mario
80b6954c29 use html2plain for summary 2021-03-17 09:13:09 +00:00
Mario
da37548e2e also move code comments to the function 2021-03-16 12:33:41 +01:00
Mario
c658bbca24 simplify get_pending_accounts query so that it will work in postgres. this will introduce a regression in rendering the table background color. 2021-03-16 12:32:20 +01:00
Mario
3b9a9db664 fix cover photo image issues on some mobile devices
(cherry picked from commit 4e921cfdcf)
2021-03-16 10:13:55 +01:00
Mario
4e921cfdcf fix cover photo image issues on some mobile devices 2021-03-16 09:09:13 +00:00
Mario
bd24224b76 air: fix register notifications 2021-03-15 12:45:39 +00:00
Mario
a5ac388889 air: fix calculate_adue() to return false if the value is zero and do not hardcode regexpire - adding the max setting (99 years) should be fine. 2021-03-15 10:31:23 +00:00
Mario
4be123dc84 fix default value displayed if value is set to empty or zero. fix #1536 and #1537 2021-03-15 10:10:08 +00:00
Mario
becb898a51 more changelog
(cherry picked from commit 268464ccde)
2021-03-15 09:36:37 +01:00
Mario
268464ccde more changelog 2021-03-15 08:36:00 +00:00
Mario
57aa96c412 changelog
(cherry picked from commit cb74de7472)
2021-03-15 09:34:00 +01:00
Mario
cb74de7472 changelog 2021-03-15 08:33:26 +00:00
Mario
d35849c418 Merge branch 'dev' into air 2021-03-14 20:29:29 +00:00
Mario
a9a112e063 php8: fix some undefined variables
(cherry picked from commit ed64eba13a)
2021-03-14 21:25:45 +01:00
Mario
1e87fe6b49 cleanup
(cherry picked from commit 0fbd0ca416)
2021-03-14 21:24:56 +01:00
Mario
ed64eba13a php8: fix some undefined variables 2021-03-14 20:23:33 +00:00
Mario
0fbd0ca416 cleanup 2021-03-14 19:23:02 +00:00
Max Kostikov
0a31267b1b Fix plurals variable 2021-03-14 11:43:47 +00:00
Mario
97c7b010ed mod subthread issue continued
(cherry picked from commit b6d30f6734)
2021-03-14 10:03:03 +01:00
Mario
b6d30f6734 mod subthread issue continued 2021-03-14 09:01:12 +00:00
Mario
b9e1c38773 fix mod subthread for zot6
(cherry picked from commit 22d769ecae)
2021-03-13 23:22:08 +01:00
Mario
22d769ecae fix mod subthread for zot6 2021-03-13 22:13:17 +00:00
Mario
45ecd1b127 revert default profile image 2021-03-12 10:50:25 +00:00
Mario
3f053611bd Merge branch 'dev' into air 2021-03-12 10:07:15 +00:00
Mario
1582b8bc96 truncate too long text 2021-03-12 09:54:01 +00:00
Mario
432e7e9714 revert follow_failover hook - there is a cleaner solution 2021-03-12 09:06:20 +00:00
Mario
31e237729c introduce the follow_failover hook 2021-03-11 21:58:45 +00:00
Mario
d2b03f6a9b more add interactive flag 2021-03-11 20:11:05 +00:00
Mario
51fe5ec982 add interactive flag 2021-03-11 19:33:03 +00:00
Mario
ce9b01ce84 Merge branch 'php8fixes' into 'dev'
Stricter item array checks

See merge request hubzilla/core!1925
2021-03-11 17:51:14 +00:00
Max Kostikov
024b489af9 Stricter item array checks 2021-03-11 17:51:13 +00:00
Mario
f980c2e3de php8: daily warning fixes (deriving from mod network) 2021-03-11 13:03:54 +00:00
Mario
db0e1c9f31 save the rewritten llink 2021-03-11 08:25:26 +00:00
Mario
260c518562 if rewriting the mid also rewrite the llink 2021-03-10 20:44:20 +00:00
Mario
689603de82 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-03-10 20:35:13 +00:00
Mario
b51049227f fix mod display query 2021-03-10 20:34:47 +00:00
Max Kostikov
0a86efc631 Merge branch 'php8fixes' into 'dev'
Check for HTTP port use on URL build

See merge request hubzilla/core!1924
2021-03-10 19:52:05 +00:00
Max Kostikov
f8467845d2 Check for HTTP port use 2021-03-10 19:44:54 +00:00
Max Kostikov
9098bb431c Check for HTTP port use 2021-03-10 19:44:17 +00:00
Max Kostikov
86ed4f4f99 Check for HTTP port use 2021-03-10 19:44:02 +00:00
Max Kostikov
7795224e70 Check for HTTP port use 2021-03-10 19:43:42 +00:00
Max Kostikov
b729cee9e4 Merge branch 'dev' into 'dev'
Dev sync

See merge request kostikov/core!1
2021-03-10 19:41:46 +00:00
Mario
15bc5c64f3 php8: isset() returns true if the array key exists but is empty. We need to check with empty() here. 2021-03-10 16:28:05 +00:00
Mario
440a132c6b Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-03-10 13:18:12 +00:00
Mario
f8447521a8 php8: random fixes deriving from mod network 2021-03-10 13:16:08 +00:00
Mario
c8050ea865 Merge branch 'php8fixes' into 'dev'
More PHP 8 fixes

See merge request hubzilla/core!1923
2021-03-10 11:14:03 +00:00
Max Kostikov
11d831e4d7 More PHP 8 fixes 2021-03-10 11:14:02 +00:00
Mario
15faf01ec9 do not parse bbcode in summary - issue #1532 2021-03-10 11:09:49 +00:00
Mario Vavti
7ee495624e a possible fix for issue #1529 2021-03-09 21:36:28 +01:00
Mario Vavti
45cc2d7bd8 changelog 2021-03-09 19:53:25 +01:00
Max Kostikov
15b45af550 Revert "Check if we have an observer xchan"
This reverts commit 91ebfbc215
2021-03-09 16:59:44 +01:00
Max Kostikov
91ebfbc215 Check if we have an observer xchan 2021-03-09 15:58:26 +00:00
Mario
ee40cb337a Merge branch 'php8-netstream' into 'dev'
Fix network stream scrolling with PHP 8

See merge request hubzilla/core!1922
2021-03-09 11:05:43 +00:00
Max Kostikov
bdae290ec4 Revert "More checks on note decoding"
This reverts commit 20199f7aee34dbc7a8aebcd459ef6cb84cdb5bd7
2021-03-09 11:05:43 +00:00
Mario
53c3d0d53d Merge branch 'php8' into 'dev'
Stricter parameters checks for PHP 8 support

See merge request hubzilla/core!1921
2021-03-09 11:02:28 +00:00
Mario
ed981ec8e8 fix profile not found if not logged in 2021-03-09 10:47:13 +00:00
Max Kostikov
723d757091 Change set_linkified_perms() arguments order 2021-03-09 09:08:33 +00:00
Max Kostikov
92ada6eb98 Change set_linkified_perms() arguments order 2021-03-09 09:07:47 +00:00
Max Kostikov
975d8ef0c7 Fix deprecated function arguments order 2021-03-09 09:06:16 +00:00
Max Kostikov
65e9ff357b More checks on note decode 2021-03-08 21:16:24 +00:00
Max Kostikov
66495e6838 Check propeties existance on note decode 2021-03-08 21:06:26 +00:00
Max Kostikov
efe65e1ba8 Fix undefined edited and created checks 2021-03-08 20:57:02 +00:00
Max Kostikov
6b500ee3e1 Check if BBcode field exist 2021-03-08 20:52:39 +00:00
Max Kostikov
1ad6308f97 Formatting 2021-03-08 20:43:29 +00:00
Max Kostikov
5d82bf946e Check if properties were provided on taxonomy decode 2021-03-08 20:35:03 +00:00
Max Kostikov
c8fe56e57d Check if oStatus conversation exists 2021-03-08 20:30:14 +00:00
Max Kostikov
88b6353465 More checks on attachments decode 2021-03-08 20:13:08 +00:00
Max Kostikov
4afddabe15 Fix missed tag warning on decode taxonomy 2021-03-08 20:09:49 +00:00
Max Kostikov
360ae9080e Fix actor store warnings on non defined properties 2021-03-08 20:06:36 +00:00
Max Kostikov
956aec1448 Check if item have a mention 2021-03-08 20:00:59 +00:00
Max Kostikov
4bcd093bef Check for attachments in item 2021-03-08 19:50:55 +00:00
Max Kostikov
f62b294a72 Check if terms are defined as array for item 2021-03-08 19:46:27 +00:00
Max Kostikov
c2adf1dcd1 Check if 'attach' and 'iconfig' array are defined 2021-03-08 19:40:40 +00:00
Mario
0932d2a0a6 fix summary not reset on cancel 2021-03-08 19:40:32 +00:00
Max Kostikov
e451284256 Check if port in the site URL provided 2021-03-08 19:35:45 +00:00
Mario
49f12695cf Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-03-08 19:25:12 +00:00
Mario
8d26961639 fix summary not saved in browser autosave draft 2021-03-08 19:25:01 +00:00
Max Kostikov
c9ec5043b9 Check if HTTP port is defined 2021-03-08 19:22:17 +00:00
Max Kostikov
03bfb8a46f Define $sql_extra2 variable before extending 2021-03-08 19:21:38 +00:00
Max Kostikov
0c5a7ab19b Define $sql_extra2 variable before concatenation 2021-03-08 19:16:41 +00:00
Mario
1561e4a89c Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-03-08 19:15:39 +00:00
Mario
b09cbb72fb type submit should not be type button 2021-03-08 19:14:14 +00:00
Mario
d57f4a9527 fix unexpected trigger of buttons when pressing enter in input field issue #1528 2021-03-08 19:12:37 +00:00
Mario
0e015d52a5 Merge branch 'dev' into 'dev'
Fix undefined page end on non dynamic pages

See merge request hubzilla/core!1920
2021-03-08 19:08:50 +00:00
Max Kostikov
7e0416ac97 Remove unusable variable $sql_query 2021-03-08 19:05:03 +00:00
Max Kostikov
98112497ba Fix Spanish plural expression 2021-03-08 15:59:12 +00:00
Max Kostikov
f952d65cfd Fix Spanish plural expression 2021-03-08 15:48:44 +00:00
Max Kostikov
182dec3e57 Fix undefined page end on non dynamic pages 2021-03-08 15:33:26 +00:00
Max Kostikov
8ab6076566 Merge branch 'dev' into 'dev'
# Conflicts:
#   boot.php
2021-03-08 15:20:38 +00:00
mjfriaza
6506cab55b Update Spanish 2021-03-08 10:28:26 +00:00
Mario
fe638c88e0 fix dev version 2021-03-08 10:16:00 +00:00
Max Kostikov
cf7f380568 Merge branch 'dev' into 'dev'
# Conflicts:
#   boot.php
2021-03-03 20:05:37 +00:00
Max Kostikov
7e36727ce6 Fix frame-src CSP error on video embedding 2021-03-03 20:01:39 +00:00
Hilmar R
c29261487c a bit more useability for the admin at the beginning 2021-03-03 12:59:19 +01:00
Hilmar R
c3229643d0 embarrassing :-( 2021-03-02 22:23:58 +01:00
Hilmar R
2b03e51bfc did2 chk num 5...10 2021-03-02 18:45:13 +01:00
Hilmar R
4cc72db463 hope not to hurry too fast when saying 5.4RC2. But today & tomorrow is only for the tests 2021-03-02 16:11:18 +01:00
Hilmar R
d434490bdf melt include/account 2021-03-02 15:54:51 +01:00
Hilmar R
2c15efbf48 Merge branch 'dev' of https://framagit.org/hubzilla/core into dev 2021-03-01 20:26:44 +01:00
Hilmar R
c26dede97f get dev 2021-03-01 18:48:11 +01:00
Max Kostikov
1d899d387e Merge branch 'dev' into 'dev'
Dev sync

See merge request kostikov/core!2
2021-02-27 19:47:26 +00:00
Hilmar R
ea3390d626 adjust air.5 to be in sync with 5.2.2 2021-02-26 15:10:24 +01:00
Hilmar R
a04ded9cca repair dd tag and set unique vsn 2021-02-26 14:38:41 +01:00
Andrzej Budziński
f4ecc0dfb9 Fixes:
- view/pl/hmessages.mo
- view/pl/hmessages.po
- view/pl/hstrings.php
2021-02-05 04:11:52 +01:00
Andrzej Budziński
111ae9812c Fixes:
- view/pl/hmessages.mo
- view/pl/hmessages.po
- view/pl/hstrings.php
2021-02-04 23:53:25 +01:00
Andrzej Budziński
ba73845bad Merge branch 'dev' into translation-pl 2021-02-03 15:00:24 +01:00
Andrzej Budziński
7ece28b981 Fixes:
- view/pl/hmessages.mo
- view/pl/hmessages.po
- view/pl/hstrings.php
2021-02-03 14:58:06 +01:00
Andrzej Budziński
5799a073fe Fixes:
- doc/pl/admin/administrator_guide.md
- doc/pl/about/project.bb
- doc/pl/TermsOfService.md
2021-02-03 02:19:27 +01:00
Andrzej Budziński
85b1bc7929 Fixes:
- doc/pl/feature/additional/overview.md
2021-02-02 03:17:25 +01:00
Andrzej Budziński
de36172af3 Fixes:
- doc/pl/feature/additional/overview.md
2021-02-02 03:09:04 +01:00
Andrzej Budziński
f5fba51f5c Fixes:
- doc/context/pl/settings/features/help.html: fixes
2021-02-02 03:00:19 +01:00
Andrzej Budziński
a2185c7886 Polish translatons - fixes, typos, and new translation
1) view/pl/messages.po: fixes & typos
2) doc/pl/admin/administrator_guide.md: fixes & typs
3) doc/pl/feature/*: new translations (needed work yet)
4) doc/pl/Features.md: fixes
5) doc/context/pl/cards/help.html: fixes
6) doc/context/pl/settings/features/help.html: fixes
7) doc/context/pl/settings/tokens/help.html: fixes
8) view/pl/register_verify_member.tpl: fixes
2021-02-02 02:50:13 +01:00
Hilmar R
fae5515350 forgotten docs 2021-01-30 23:19:03 +01:00
Hilmar R
68d5969d33 validate,invite 2021-01-30 23:15:13 +01:00
Hilmar R
3773bceb46 context help register en,de 2021-01-29 23:25:47 +01:00
Hilmar R
4ecb4189b8 Register panel interaction consistence usage 2021-01-28 22:08:38 +01:00
Hilmar R
d0d6170a71 login panel, reg limits. 2021-01-27 00:20:18 +01:00
Hilmar R
cd98e75a42 Two field positions 2021-01-24 23:53:28 +01:00
Hilmar R
3f031399cb auto channel create adjustments 2021-01-24 20:59:11 +01:00
Hilmar R
0a16674f6e auto channel create adjustments, zar log reg msgs 2021-01-24 16:44:58 +01:00
Hilmar R
9365b8691e 2 fields dups removed 2021-01-23 23:58:20 +01:00
Hilmar R
33825ba0b4 typo 2021-01-23 16:08:16 +01:00
Hilmar R
67db1c6e9b melt diff prod fork 4.6.2 air onto 5.2.1 to 5.2.2 DB 1241 2021-01-23 15:24:24 +01:00
Hilmar R
abdf6f40a2 at end of day, some files probably without conflicts so far 2021-01-23 00:08:25 +01:00
Hilmar R
523765b968 Merge branch 'master' into air.5 2021-01-22 01:38:43 +01:00
me
78f150cfbc air.s1: field templates checkbox/input/select and one new 2020-11-14 23:37:18 +01:00
196 changed files with 18441 additions and 11905 deletions

View File

@@ -1,3 +1,47 @@
Hubzilla 5.6 (2021-05-11)
- Improve postgres hubloc queries
- Implement automatic duplicate singleton hubloc removal
- Send author id, id_sig and key fields along with author/owner
- Implement custom redis session backend
- Improved registration workflow
- Complete rewrite of the registration backend with many new features
- Complete rewrite of the invite app
- Update Spanish, Russian and Polish translations
- Improved PHP8 compatibiliy (work in progress)
Bugfixes
- Fix manual fetching of non-ascii domains
- Fix revision not compared when importing items
- Fix events not transformed to UTC when importing calendar
- Fix timezone issue in mod cal
- Fix profile photos not revalidated
- Fix regression in caldav/carddav discovery
- Fix caldav/carddav sync on remote access
- Fix info and notice messages not bootstraped when using SSE
- Fix URL including an @ treated like a webbie
- Fix cover photo image issues on some mobile devices
Addons
- Diaspora: improve performance when delivering public items
- Diaspora: make sure to not process same contact more than once
- Pubcrawl: make sure to not process same contact more than once
- Pubcrawl: do not relay Like and Dislike activity
- Pubcrawl: deprecate as_follow() in favour of core Activity::follow()
- Pubcrawl: improved compatibility with mobilizon and xwiki
- Pubcrawl: do not process follow/unfollw thread in as_create_note()
- Diaspora: do not relay comments/likes of strangers if the thread-owner is local and does not allow comments/likes by strangers in the diaspora app settings
Hubzilla 5.4.3 (2021-04-20)
- Fix regression in mod notifications (only the last was visible)
- Set Permissions-Policy: interest-cohort=() header by default
- Fix xchans containing a % breaking get_forum_channels()
- Fix webfinger if using a reverse proxy
- Fix regression finding bookmarks
- Fix zot6 hublocs import on channel import
- Fix revision not checked in import_items()
Hubzilla 5.4.2 (2021-03-15)
- Fix translation plural variable
- Fix issue with following/unfollowing a thread

48
CHANGELOG.air Normal file
View File

@@ -0,0 +1,48 @@
"air" is a branch name for revision of Account-Invite-Register at the Hubzilla project
Invite:
* Rewritten and now language template driven
* Selectable templates for the invite mails
* Invitor may add personal notes in the mailtext
+ Invite codes are bound to the recipients email address
* Invite mod never more creates accounts
* new db scheme for table register
* existing register table will be migrated to the new schema even when detected at runtime
* Bugfix: creating invite codes when admin only calls Invite w/o any further action
* account library revision also together with invite mod
* Depending on config: Users may send invitations also
* Invitations expires, controlled by the invitor
* Changed and new configs:
* * invitation_only As usual before
* * invitation_also Beside other registration policies, invitations may be used also
* * invitation_max_per_day defaults 50, may be changed in adminUI admin>site
* * invitation_max_per_user defaults 4
* Requirements:
* * Addon language has to be installed
Register:
* Register panel (form) and js interaction changed
* Unused registrations expire
* Depending on config, anonymous registrations (w/o email) are supported
* :... dont't panic, that may let grow security
* Even anonymous users have to confirm their registration
* Registrations may be enabled / disabled time driven for each day in the week (dudy)
* Unsoliced registration floods may be blocked
* Limited registrations from one single source ip
* Using one additional log file, to easy interfare with f2b
Account:
* An user account always becomes created only if all depending conditions are satisfied
* AdminUI for site configuration, accounts and registrations enhancements
* Still untouched, but accountUI needs enhanced async control in case for mass delete
with deep level of recursion cascade of the dependencies (channels etc). An open TODO
since years for instances with many much users and channels.
History:
2020.03 Hubzilla Prod version 4.6 (master branch) of hubzilla/core was the base for AIR
that was assigned Version 4.6.2 at sn/core
2021.02 Hubzilla Prod version 5.2.1 (master branch) of hubzilla/core was new base for AIR
that was assigned version 5.2.2 at sn/core (air.5)
plus adjustment of hubzilla 5.2.2 (master) to sn/core (air.5) version 5.2.9

View File

@@ -55,11 +55,13 @@ class Cron {
db_utcnow()
);
remove_expired_registrations();
$interval = get_config('system', 'delivery_interval', 3);
// expire any expired items
$r = q("select id,item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
$r = q("select id,item_wall from item where expires > '2001-01-01 00:00:00' and expires < %s
and item_deleted = 0 ",
db_utcnow()
);
@@ -131,7 +133,7 @@ class Cron {
// publish any applicable items that were set to be published in the future
// (time travel posts). Restrict to items that have come of age in the last
// couple of days to limit the query to something reasonable.
// couple of days to limit the query to something reasonable.
$r = q("select id from item where item_delayed = 1 and created <= %s and created > '%s' ",
db_utcnow(),
@@ -192,7 +194,7 @@ class Cron {
// update any photos which didn't get imported properly
// This should be rare
$r = q("select xchan_photo_l, xchan_hash from xchan where xchan_photo_l != '' and xchan_photo_m = ''
$r = q("select xchan_photo_l, xchan_hash from xchan where xchan_photo_l != '' and xchan_photo_m = ''
and xchan_photo_date < %s - INTERVAL %s",
db_utcnow(),
db_quoteinterval('1 DAY')
@@ -238,7 +240,7 @@ class Cron {
set_config('system', 'lastcron', datetime_convert());
//All done - clear the lockfile
//All done - clear the lockfile
@unlink($lockfile);
return;

View File

@@ -93,6 +93,7 @@ class Cron_daily {
Master::Summon(array('Cli_suggest'));
remove_obsolete_hublocs();
remove_duplicate_singleton_hublocs();
z6_discover();

View File

@@ -28,7 +28,7 @@ class Queue {
if ($r) {
foreach ($r as $rr) {
$h = parse_url($rr['outq_posturl']);
$desturl = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : '');
$desturl = $h['scheme'] . '://' . $h['host'] . (isset($h['port']) ? ':' . $h['port'] : '');
q("update site set site_dead = 1 where site_dead = 0 and site_url = '%s' and site_update < %s - INTERVAL %s",
dbesc($desturl),
db_utcnow(), db_quoteinterval('1 MONTH')

View File

@@ -104,7 +104,10 @@ class Activity {
if ($x['success']) {
$m = parse_url($url);
if ($m) {
$site_url = unparse_url(['scheme' => $m['scheme'], 'host' => $m['host'], 'port' => $m['port'] ]);
$y = [ 'scheme' => $m['scheme'], 'host' => $m['host'] ];
if (array_key_exists('port', $m))
$y['port'] = $m['port'];
$site_url = unparse_url($y);
q("UPDATE site SET site_update = '%s', site_dead = 0 WHERE site_url = '%s' AND site_update < %s - INTERVAL %s",
dbesc(datetime_convert()),
dbesc($site_url),
@@ -129,8 +132,8 @@ class Activity {
}
static function fetch_profile($x) {
$r = q("select * from xchan where xchan_url like '%s' limit 1",
dbesc($x['id'] . '/%')
$r = q("select * from xchan where xchan_url = '%s' limit 1",
dbesc($x['id'])
);
if (!$r) {
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
@@ -572,7 +575,7 @@ class Activity {
$ret = [];
if ($item['tag'] && is_array($item['tag'])) {
if (array_key_exists('tag', $item) && is_array($item['tag'])) {
$ptr = $item['tag'];
if (!array_key_exists(0, $ptr)) {
$ptr = [$ptr];
@@ -581,23 +584,25 @@ class Activity {
if (!array_key_exists('type', $t))
$t['type'] = 'Hashtag';
switch ($t['type']) {
case 'Hashtag':
$ret[] = ['ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '#') ? substr($t['name'], 1) : $t['name'])];
break;
if (array_key_exists('href', $t) && array_key_exists('name', $t)) {
switch ($t['type']) {
case 'Hashtag':
$ret[] = ['ttype' => TERM_HASHTAG, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '#') ? substr($t['name'], 1) : $t['name'])];
break;
case 'Mention':
$mention_type = substr($t['name'], 0, 1);
if ($mention_type === '!') {
$ret[] = ['ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'], 1))];
}
else {
$ret[] = ['ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '@') ? substr($t['name'], 1) : $t['name'])];
}
break;
case 'Mention':
$mention_type = substr($t['name'], 0, 1);
if ($mention_type === '!') {
$ret[] = ['ttype' => TERM_FORUM, 'url' => $t['href'], 'term' => escape_tags(substr($t['name'], 1))];
}
else {
$ret[] = ['ttype' => TERM_MENTION, 'url' => $t['href'], 'term' => escape_tags((substr($t['name'], 0, 1) === '@') ? substr($t['name'], 1) : $t['name'])];
}
break;
default:
break;
default:
break;
}
}
}
}
@@ -609,7 +614,7 @@ class Activity {
$ret = [];
if ($item['term']) {
if (array_key_exists('term', $item) && is_array($item['term'])) {
foreach ($item['term'] as $t) {
switch ($t['ttype']) {
case TERM_HASHTAG:
@@ -640,7 +645,7 @@ class Activity {
$ret = [];
if ($item['attach']) {
if (array_key_exists('attach', $item)) {
$atts = ((is_array($item['attach'])) ? $item['attach'] : json_decode($item['attach'], true));
if ($atts) {
foreach ($atts as $att) {
@@ -653,7 +658,7 @@ class Activity {
}
}
}
if ($item['iconfig']) {
if (array_key_exists('iconfig', $item) && is_array($item['iconfig'])) {
foreach ($item['iconfig'] as $att) {
if ($att['sharing']) {
$value = ((is_string($att['v']) && preg_match('|^a:[0-9]+:{.*}$|s', $att['v'])) ? unserialize($att['v']) : $att['v']);
@@ -697,16 +702,16 @@ class Activity {
$ret = [];
if ($item['attachment']) {
if (array_key_exists('attachment', $item) && is_array($item['attachment'])) {
foreach ($item['attachment'] as $att) {
$entry = [];
if ($att['href'])
if (array_key_exists('href', $att))
$entry['href'] = $att['href'];
elseif ($att['url'])
elseif (array_key_exists('url', $att))
$entry['href'] = $att['url'];
if ($att['mediaType'])
if (array_key_exists('mediaType', $att))
$entry['type'] = $att['mediaType'];
elseif ($att['type'] === 'Image')
elseif (array_key_exists('type', $att) && $att['type'] === 'Image')
$entry['type'] = 'image/jpeg';
if ($entry)
$ret[] = $entry;
@@ -978,19 +983,17 @@ class Activity {
// Returns an array of URLS for any mention tags found in the item array $i.
static function map_mentions($i) {
if (!$i['term']) {
return [];
}
$list = [];
foreach ($i['term'] as $t) {
if (!$t['url']) {
continue;
}
if ($t['ttype'] == TERM_MENTION) {
$url = self::lookup_term_url($t['url']);
$list[] = (($url) ? $url : $t['url']);
if (array_key_exists('term', $i) && is_array($i['term'])) {
foreach ($i['term'] as $t) {
if (!$t['url']) {
continue;
}
if ($t['ttype'] == TERM_MENTION) {
$url = self::lookup_term_url($t['url']);
$list[] = (($url) ? $url : $t['url']);
}
}
}
@@ -1091,18 +1094,7 @@ class Activity {
'height' => 300,
'width' => 300,
];
$ret['url'] = [
[
'type' => 'Link',
'mediaType' => 'text/html',
'href' => $p['xchan_url']
],
[
'type' => 'Link',
'mediaType' => 'text/x-zot+json',
'href' => $p['xchan_url']
]
];
$ret['url'] = $p['xchan_url'];
$ret['publicKey'] = [
'id' => $p['xchan_url'],
@@ -1331,12 +1323,12 @@ class Activity {
*
*/
$person_obj = $act->actor;
if ($act->type === 'Follow') {
if (in_array($act->type, [ 'Follow', 'Invite', 'Join'])) {
$their_follow_id = $act->id;
}
$person_obj = (($act->type == 'Invite') ? $act->obj : $act->actor);
if (is_array($person_obj)) {
// store their xchan and hubloc
@@ -1354,9 +1346,8 @@ class Activity {
}
}
$x = PermissionRoles::role_perms('social');
$p = Permissions::FilledPerms($x['perms_connect']);
$their_perms = Permissions::serialise($p);
$x = \Zotlabs\Access\PermissionRoles::role_perms('social');
$their_perms = \Zotlabs\Access\Permissions::FilledPerms($x['perms_connect']);
if ($contact && $contact['abook_id']) {
@@ -1365,18 +1356,18 @@ class Activity {
switch ($act->type) {
case 'Follow':
case 'Invite':
case 'Join':
// A second Follow request, but we haven't approved the first one
if ($contact['abook_pending']) {
return;
}
// We've already approved them or followed them first
// Send an Accept back to them
set_abconfig($channel['channel_id'], $person_obj['id'], 'pubcrawl', 'their_follow_id', $their_follow_id);
Master::Summon(['Notifier', 'permissions_accept', $contact['abook_id']]);
Master::Summon(['Notifier', 'permission_accept', $contact['abook_id']]);
return;
case 'Accept':
@@ -1430,8 +1421,8 @@ class Activity {
}
$ret = $r[0];
$p = Permissions::connect_perms($channel['channel_id']);
$my_perms = Permissions::serialise($p['perms']);
$p = \Zotlabs\Access\Permissions::connect_perms($channel['channel_id']);
$my_perms = $p['perms'];
$automatic = $p['automatic'];
$closeness = get_pconfig($channel['channel_id'], 'system', 'new_abook_closeness', 80);
@@ -1451,12 +1442,13 @@ class Activity {
]
);
if ($my_perms)
set_abconfig($channel['channel_id'], $ret['xchan_hash'], 'system', 'my_perms', $my_perms);
if ($their_perms)
set_abconfig($channel['channel_id'], $ret['xchan_hash'], 'system', 'their_perms', $their_perms);
if($my_perms)
foreach($my_perms as $k => $v)
set_abconfig($channel['channel_id'],$ret['xchan_hash'],'my_perms',$k,$v);
if($their_perms)
foreach($their_perms as $k => $v)
set_abconfig($channel['channel_id'],$ret['xchan_hash'],'their_perms',$k,$v);
if ($r) {
logger("New ActivityPub follower for {$channel['channel_name']}");
@@ -1477,9 +1469,9 @@ class Activity {
if ($my_perms && $automatic) {
// send an Accept for this Follow activity
Master::Summon(['Notifier', 'permissions_accept', $new_connection[0]['abook_id']]);
Master::Summon(['Notifier', 'permission_accept', $new_connection[0]['abook_id']]);
// Send back a Follow notification to them
Master::Summon(['Notifier', 'permissions_create', $new_connection[0]['abook_id']]);
Master::Summon(['Notifier', 'permission_create', $new_connection[0]['abook_id']]);
}
$clone = [];
@@ -1604,13 +1596,13 @@ class Activity {
if ($inbox) {
$collections['inbox'] = $inbox;
if ($person_obj['outbox'])
if (array_key_exists('outbox', $person_obj))
$collections['outbox'] = $person_obj['outbox'];
if ($person_obj['followers'])
if (array_key_exists('followers', $person_obj))
$collections['followers'] = $person_obj['followers'];
if ($person_obj['following'])
if (array_key_exists('following', $person_obj))
$collections['following'] = $person_obj['following'];
if ($person_obj['endpoints'] && $person_obj['endpoints']['sharedInbox'])
if (array_key_exists('endpoints', $person_obj) && array_key_exists('sharedInbox', $person_obj['endpoints']))
$collections['sharedInbox'] = $person_obj['endpoints']['sharedInbox'];
}
@@ -2123,22 +2115,22 @@ class Activity {
$s['uuid'] = $act->obj['diaspora:guid'];
$s['parent_mid'] = $act->parent_id;
if ($act->data['published']) {
if (array_key_exists('published', $act->data)) {
$s['created'] = datetime_convert('UTC', 'UTC', $act->data['published']);
}
elseif ($act->obj['published']) {
elseif (array_key_exists('published', $act->obj)) {
$s['created'] = datetime_convert('UTC', 'UTC', $act->obj['published']);
}
if ($act->data['updated']) {
if (array_key_exists('updated', $act->data)) {
$s['edited'] = datetime_convert('UTC', 'UTC', $act->data['updated']);
}
elseif ($act->obj['updated']) {
elseif (array_key_exists('updated', $act->obj)) {
$s['edited'] = datetime_convert('UTC', 'UTC', $act->obj['updated']);
}
if ($act->data['expires']) {
if (array_key_exists('expires', $act->data)) {
$s['expires'] = datetime_convert('UTC', 'UTC', $act->data['expires']);
}
elseif ($act->obj['expires']) {
elseif (array_key_exists('expires', $act->obj)) {
$s['expires'] = datetime_convert('UTC', 'UTC', $act->obj['expires']);
}
@@ -2198,10 +2190,10 @@ class Activity {
}
}
if (!$s['created'])
if (! array_key_exists('created', $s))
$s['created'] = datetime_convert();
if (!$s['edited'])
if (! array_key_exists('edited', $s))
$s['edited'] = $s['created'];
$s['title'] = (($response_activity) ? EMPTY_STR : self::bb_content($content, 'name'));
@@ -2315,7 +2307,7 @@ class Activity {
}
}
if ($act->obj['closed']) {
if (array_key_exists('closed', $act->obj)) {
$s['comments_closed'] = datetime_convert('UTC', 'UTC', $act->obj['closed']);
}
@@ -2731,7 +2723,7 @@ class Activity {
}
}
if ($act->obj['conversation']) {
if (array_key_exists('conversation', $act->obj)) {
set_iconfig($item, 'ostatus', 'conversation', $act->obj['conversation'], 1);
}
@@ -3384,22 +3376,25 @@ class Activity {
require_once('include/event.php');
$ret = false;
if (is_array($content[$field])) {
foreach ($content[$field] as $k => $v) {
$ret .= html2bbcode($v);
// save this for auto-translate or dynamic filtering
// $ret .= '[language=' . $k . ']' . html2bbcode($v) . '[/language]';
}
}
else {
if ($field === 'bbcode' && array_key_exists('bbcode', $content)) {
$ret = $content[$field];
if (array_key_exists($field, $content)) {
if (is_array($content[$field])) {
foreach ($content[$field] as $k => $v) {
$ret .= html2bbcode($v);
// save this for auto-translate or dynamic filtering
// $ret .= '[language=' . $k . ']' . html2bbcode($v) . '[/language]';
}
}
else {
$ret = html2bbcode($content[$field]);
if ($field === 'bbcode' && array_key_exists('bbcode', $content)) {
$ret = $content[$field];
}
else {
$ret = html2bbcode($content[$field]);
}
}
}
if ($field === 'content' && $content['event'] && (!strpos($ret, '[event'))) {
if ($field === 'content' && array_key_exists('event', $content) && (!strpos($ret, '[event'))) {
$ret .= format_event_bbcode($content['event']);
}

View File

@@ -551,7 +551,7 @@ class Apps {
'$app' => $papp,
'$icon' => $icon,
'$hosturl' => $hosturl,
'$purchase' => (($papp['page'] && (! $installed)) ? t('Purchase') : ''),
'$purchase' => ((isset($papp['page']) && (! $installed)) ? t('Purchase') : ''),
'$installed' => $installed,
'$action_label' => (($hosturl && in_array($mode, ['view','install'])) ? $install_action : ''),
'$edit' => ((local_channel() && $installed && $mode == 'edit') ? t('Edit') : ''),
@@ -559,8 +559,8 @@ class Apps {
'$undelete' => ((local_channel() && $mode == 'edit') ? t('Undelete') : ''),
'$settings_url' => ((local_channel() && $installed && $mode == 'list') ? $papp['settings_url'] : ''),
'$deleted' => $papp['deleted'],
'$feature' => (($papp['embed'] || $mode == 'edit') ? false : true),
'$pin' => (($papp['embed'] || $mode == 'edit') ? false : true),
'$feature' => ((isset($papp['embed']) || $mode == 'edit') ? false : true),
'$pin' => ((isset($papp['embed']) || $mode == 'edit') ? false : true),
'$featured' => ((strpos($papp['categories'], 'nav_featured_app') === false) ? false : true),
'$pinned' => ((strpos($papp['categories'], 'nav_pinned_app') === false) ? false : true),
'$navapps' => (($mode == 'nav') ? true : false),
@@ -1276,58 +1276,58 @@ class Apps {
$ret['type'] = 'personal';
if($app['app_id'])
if(!empty($app['app_id']))
$ret['guid'] = $app['app_id'];
if($app['app_sig'])
if(!empty($app['app_sig']))
$ret['sig'] = $app['app_sig'];
if($app['app_author'])
if(!empty($app['app_author']))
$ret['author'] = $app['app_author'];
if($app['app_name'])
if(!empty($app['app_name']))
$ret['name'] = $app['app_name'];
if($app['app_desc'])
if(!empty($app['app_desc']))
$ret['desc'] = $app['app_desc'];
if($app['app_url'])
if(!empty($app['app_url']))
$ret['url'] = $app['app_url'];
if($app['app_photo'])
if(!empty($app['app_photo']))
$ret['photo'] = $app['app_photo'];
if($app['app_icon'])
if(!empty($app['app_icon']))
$ret['icon'] = $app['app_icon'];
if($app['app_version'])
if(!empty($app['app_version']))
$ret['version'] = $app['app_version'];
if($app['app_addr'])
if(!empty($app['app_addr']))
$ret['addr'] = $app['app_addr'];
if($app['app_price'])
if(!empty($app['app_price']))
$ret['price'] = $app['app_price'];
if($app['app_page'])
if(!empty($app['app_page']))
$ret['page'] = $app['app_page'];
if($app['app_requires'])
if(!empty($app['app_requires']))
$ret['requires'] = $app['app_requires'];
if($app['app_system'])
if(!empty($app['app_system']))
$ret['system'] = $app['app_system'];
if($app['app_options'])
if(!empty($app['app_options']))
$ret['options'] = $app['app_options'];
if($app['app_plugin'])
if(!empty($app['app_plugin']))
$ret['plugin'] = trim($app['app_plugin']);
if($app['app_deleted'])
if(!empty($app['app_deleted']))
$ret['deleted'] = $app['app_deleted'];
if($app['term']) {
if(!empty($app['term']) && is_array($app['term'])) {
$s = '';
foreach($app['term'] as $t) {
if($s)

View File

@@ -207,13 +207,13 @@ class Connect {
}
$my_perms = $p['perms'];
$profile_assign = get_pconfig($uid,'system','profile_assign','');
// See if we are already connected by virtue of having an abook record
$r = q("select abook_id, abook_xchan, abook_pending, abook_instance from abook
$r = q("select abook_id, abook_xchan, abook_pending, abook_instance from abook
where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($xchan_hash),
intval($uid)
@@ -282,7 +282,7 @@ class Connect {
// fetch the entire record
$r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash
$r = q("select abook.*, xchan.* from abook left join xchan on abook_xchan = xchan_hash
where abook_xchan = '%s' and abook_channel = %d limit 1",
dbesc($xchan_hash),
intval($uid)

View File

@@ -978,12 +978,12 @@ class Enotify {
$x = [
'notify_link' => z_root() . '/admin/accounts',
'name' => $rr['account_email'],
//'addr' => $rr['account_email'],
'name' => $rr['reg_did2'],
//'addr' => '',
'photo' => z_root() . '/' . get_default_profile_photo(48),
'when' => datetime_convert('UTC', date_default_timezone_get(),$rr['account_created']),
'when' => datetime_convert('UTC', date_default_timezone_get(),$rr['reg_created']),
'hclass' => ('notify-unseen'),
'message' => t('requires approval')
'message' => t('status verified')
];
return $x;

View File

@@ -716,6 +716,9 @@ class Libsync {
dbesc($sender['hash'])
);
if(!$xisting)
$xisting = [];
// See if a primary is specified
$has_primary = false;
@@ -781,7 +784,7 @@ class Libsync {
$t = datetime_convert('UTC', 'UTC', 'now - 15 minutes');
if (array_key_exists('site', $arr) && $location['url'] == $arr['site']['url']) {
q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d and hubloc_connected < '%s'",
q("update hubloc set hubloc_connected = '%s', hubloc_updated = '%s' where hubloc_id = %d and hubloc_updated < '%s'",
dbesc(datetime_convert()),
dbesc(datetime_convert()),
intval($r[0]['hubloc_id']),

View File

@@ -299,7 +299,6 @@ class Libzot {
}
$record = Zotfinger::exec($url, $channel);
// Check the HTTP signature
$hsig = $record['signature'];
@@ -2665,9 +2664,9 @@ class Libzot {
// we may only end up with one; which results in posts with no author name or photo and are a bit
// of a hassle to repair. If either or both are missing, do a full discovery probe.
if (!array_key_exists('id', $x)) {
return import_author_activitypub($x);
}
//if (!array_key_exists('id', $x)) {
//return import_author_activitypub($x);
//}
$hash = self::make_xchan_hash($x['id'], $x['key']);

View File

@@ -101,6 +101,7 @@ class NativeWiki {
}
}
public static function update_wiki($channel_id, $observer_hash, $arr, $acl) {
$w = self::get_wiki($channel_id, $observer_hash, $arr['resource_id']);
@@ -156,8 +157,8 @@ class NativeWiki {
}
}
public static function sync_a_wiki_item($uid,$id,$resource_id) {
public static function sync_a_wiki_item($uid,$id,$resource_id) {
$r = q("SELECT * from item WHERE uid = %d AND ( id = %d OR ( resource_type = '%s' and resource_id = '%s' )) ",
intval($uid),
@@ -165,8 +166,8 @@ class NativeWiki {
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
dbesc($resource_id)
);
if($r) {
$q = q("select * from item where resource_type = 'nwikipage' and resource_id = '%s'",
dbesc($r[0]['resource_id'])
);
@@ -185,20 +186,27 @@ class NativeWiki {
}
}
public static function delete_wiki($channel_id,$observer_hash,$resource_id) {
$w = self::get_wiki($channel_id,$observer_hash,$resource_id);
$item = $w['wiki'];
if(! $item) {
return array('item' => null, 'success' => false);
}
else {
$drop = drop_item($item['id'], false, DROPITEM_NORMAL);
if(! $w['wiki']) {
return [ 'success' => false ];
}
else {
info( t('Wiki files deleted successfully'));
$r = q("SELECT id FROM item WHERE uid = %s AND resource_id = '%s'",
intval($channel_id),
dbesc($resource_id)
);
return array('item' => $item, 'item_id' => $item['id'], 'success' => (($drop === 1) ? true : false));
$ids = array_column($r, 'id');
drop_items($ids, true, DROPITEM_PHASE1);
info(t('Wiki files deleted successfully'));
return [ 'success' => true ];
}
}
@@ -207,13 +215,13 @@ class NativeWiki {
$sql_extra = item_permissions_sql($channel_id,$observer_hash);
$item = q("SELECT * FROM item WHERE uid = %d AND resource_type = '%s' AND resource_id = '%s' AND item_deleted = 0
$sql_extra limit 1",
$sql_extra ORDER BY id LIMIT 1",
intval($channel_id),
dbesc(NWIKI_ITEM_RESOURCE_TYPE),
dbesc($resource_id)
);
if(! $item) {
return array('wiki' => null);
return [ 'wiki' => null ];
}
else {
@@ -259,6 +267,7 @@ class NativeWiki {
public static function get_permissions($resource_id, $owner_id, $observer_hash) {
// TODO: For now, only the owner can edit
$sql_extra = item_permissions_sql($owner_id, $observer_hash);
@@ -283,6 +292,7 @@ class NativeWiki {
}
}
public static function name_encode ($string) {
$string = html_entity_decode($string);
@@ -298,6 +308,7 @@ class NativeWiki {
return $ret;
}
public static function name_decode ($string) {
$encoding = mb_internal_encoding();

View File

@@ -109,6 +109,7 @@ class NativeWikiPage {
return [ 'success' => false, 'message' => t('Wiki page create failed.') ];
}
static public function rename_page($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
@@ -167,7 +168,9 @@ class NativeWikiPage {
}
static public function get_page_content($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
@@ -198,7 +201,9 @@ class NativeWikiPage {
}
static public function page_history($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
@@ -290,6 +295,7 @@ class NativeWikiPage {
return null;
}
static public function load_page_history($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
@@ -338,6 +344,7 @@ class NativeWikiPage {
return null;
}
static public function save_page($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$content = ((array_key_exists('content',$arr)) ? $arr['content'] : '');
@@ -389,14 +396,15 @@ class NativeWikiPage {
return array('message' => t('Page update failed.'), 'success' => false);
}
static public function delete_page($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$observer_hash = ((array_key_exists('observer_hash',$arr)) ? $arr['observer_hash'] : '');
$channel_id = ((array_key_exists('channel_id',$arr)) ? $arr['channel_id'] : 0);
$pageUrlName = (array_key_exists('pageUrlName',$arr) ? $arr['pageUrlName'] : '');
$resource_id = (array_key_exists('resource_id',$arr) ? $arr['resource_id'] : '');
$observer_hash = (array_key_exists('observer_hash',$arr) ? $arr['observer_hash'] : '');
$channel_id = (array_key_exists('channel_id',$arr) ? $arr['channel_id'] : 0);
$w = Zlib\NativeWiki::get_wiki($channel_id, $observer_hash, $resource_id);
if(! $w['wiki']) {
return [ 'success' => false, 'message' => t('Error reading wiki') ];
}
@@ -416,14 +424,16 @@ class NativeWikiPage {
}
if($ids) {
drop_items($ids);
drop_items($ids, true, DROPITEM_PHASE1);
return [ 'success' => true ];
}
return [ 'success' => false, 'message' => t('Nothing deleted') ];
}
static public function revert_page($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$commitHash = ((array_key_exists('commitHash',$arr)) ? $arr['commitHash'] : null);
@@ -454,7 +464,9 @@ class NativeWikiPage {
}
}
static public function compare_page($arr) {
$pageUrlName = ((array_key_exists('pageUrlName',$arr)) ? $arr['pageUrlName'] : '');
$resource_id = ((array_key_exists('resource_id',$arr)) ? $arr['resource_id'] : '');
$currentCommit = ((array_key_exists('currentCommit',$arr)) ? $arr['currentCommit'] : (-1));
@@ -490,6 +502,7 @@ class NativeWikiPage {
}
static public function commit($arr) {
$commit_msg = ((array_key_exists('commit_msg', $arr)) ? $arr['commit_msg'] : t('Page updated'));
@@ -570,7 +583,6 @@ class NativeWikiPage {
}
/**
* Replace the instances of the string [toc] with a list element that will be populated by
* a table of contents by the JavaScript library
@@ -586,6 +598,7 @@ class NativeWikiPage {
return $s;
}
/**
* Converts a select set of bbcode tags. Much of the code is copied from include/bbcode.php
* @param string $s
@@ -625,7 +638,9 @@ class NativeWikiPage {
return $s;
}
static public function get_file_ext($arr) {
if($arr['mimetype'] === 'text/bbcode')
return '.bb';
elseif($arr['mimetype'] === 'text/markdown')

View File

@@ -116,7 +116,7 @@ class Queue {
dbesc(($arr['driver']) ? $arr['driver'] : 'zot6'),
dbesc($arr['posturl']),
intval(1),
intval(($arr['priority']) ? $arr['priority'] : 0),
intval(isset($arr['priority']) ? $arr['priority'] : 0),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
@@ -134,7 +134,7 @@ class Queue {
$base = null;
$h = parse_url($outq['outq_posturl']);
if($h !== false)
$base = $h['scheme'] . '://' . $h['host'] . (($h['port']) ? ':' . $h['port'] : '');
$base = $h['scheme'] . '://' . $h['host'] . (isset($h['port']) ? ':' . $h['port'] : '');
if(($base) && ($base !== z_root()) && ($immediate)) {
$y = q("select site_update, site_dead from site where site_url = '%s' ",

View File

@@ -43,7 +43,7 @@ class ThreadItem {
$observer = \App::get_observer();
// Prepare the children
if($data['children']) {
if(isset($data['children'])) {
foreach($data['children'] as $item) {
/*

View File

@@ -101,11 +101,14 @@ class Admin extends \Zotlabs\Web\Controller {
// pending registrations
$pdg = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d ) > 0 ",
intval(ACCOUNT_PENDING)
// $pdg = q("SELECT account.*, register.reg_hash from account left join register on account_id = register.reg_uid // where (account_flags & %d ) > 0 ",
// intval(ACCOUNT_PENDING)
// );
$pdg = q("SELECT COUNT(*) AS pdg FROM register WHERE reg_vital = 1 AND reg_expires > '%s' ",
dbesc(date('Y-m-d H:i:s'))
);
$pending = (($pdg) ? count($pdg) : 0);
$pending = ($pdg ? $pdg[0]['pdg'] : 0);
// available channels, primary and clones
$channels = array();

View File

@@ -5,7 +5,7 @@ namespace Zotlabs\Module\Admin;
class Accounts {
/**
* @brief Handle POST actions on accounts admin page.
*
@@ -15,14 +15,105 @@ class Accounts {
*
*/
const MYP = 'ZAR'; // ZAR2x
const VERSION = '2.0.0';
function post() {
$pending = ( x($_POST, 'pending') ? $_POST['pending'] : array() );
$users = ( x($_POST, 'user') ? $_POST['user'] : array() );
$blocked = ( x($_POST, 'blocked') ? $_POST['blocked'] : array() );
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts');
$isajax = is_ajax();
$rc = 0;
If (!is_site_admin()) {
if ($isajax) {
killme();
exit;
}
goaway(z_root() . '/');
}
if ($isajax) {
//$debug = print_r($_SESSION[self::MYP],true);
$zarop = (x($_POST['zardo']) && preg_match('/^[ad]{1,1}$/', $_POST['zardo']) )
? $_POST['zardo'] : '';
// zarat arrives with leading underscore _n
$zarat = (x($_POST['zarat']) && preg_match('/^_{1,1}[0-9]{1,6}$/', $_POST['zarat']) )
? substr($_POST['zarat'],1) : '';
$zarse = (x($_POST['zarse']) && preg_match('/^[0-9a-f]{8,8}$/', $_POST['zarse']) )
? hex2bin($_POST['zarse']) : '';
if ($zarop && $zarat >= 0 && $zarse && $zarse == $_SESSION[self::MYP]['h'][$zarat]) {
//
if ($zarop == 'd') {
$rd = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
intval($_SESSION[self::MYP]['i'][$zarat]),
dbesc($_SESSION[self::MYP]['h'][$zarat])
);
$rc = '×';
}
elseif ($zarop == 'a') {
// approval, REGISTER_DENIED by user 0x0040, REGISTER_AGREED by user 0x0020 @Regate
$rd = q("UPDATE register SET reg_flags = (reg_flags & ~ 16), "
. " reg_vital = (CASE (reg_flags & ~ 48) WHEN 0 THEN 0 ELSE 1 END) "
. " WHERE reg_vital = 1 AND reg_id = %d AND SUBSTR(reg_hash,1,4) = '%s' ",
intval($_SESSION[self::MYP]['i'][$zarat]),
dbesc($_SESSION[self::MYP]['h'][$zarat])
);
$rc = 0;
$rs = q("SELECT * from register WHERE reg_id = %d ",
intval($_SESSION[self::MYP]['i'][$zarat])
);
if ($rs && ($rs[0]['reg_flags'] & ~ 48) == 0) {
// create account
$rc = 'ok'.$rs[0]['reg_id'];
$ac = create_account_from_register($rs[0]);
if ( $ac['success'] ) {
$rc .= '✔';
$auto_create = get_config('system','auto_channel_create',1);
if($auto_create) {
$reonar = json_decode($rs[0]['reg_stuff'], true);
// prepare channel creation
if($reonar['chan.name'])
set_aconfig($ac['account']['account_id'], 'register', 'channel_name', $reonar['chan.name']);
if($reonar['chan.did1'])
set_aconfig($ac['account']['account_id'], 'register', 'channel_address', $reonar['chan.did1']);
$permissions_role = get_config('system','default_permissions_role');
if($permissions_role)
set_aconfig($ac['account']['account_id'], 'register', 'permissions_role', $permissions_role);
// create channel
$new_channel = auto_channel_create($ac['account']['account_id']);
if($new_channel['success']) {
$rc .= ' c,ok' . $new_channel['channel']['channel_id'] . '✔';
}
else {
$rc .= ' c ×';
}
}
}
} else {
$rc='oh ×';
}
}
echo json_encode(array('re' => $zarop, 'at' => '_' . $zarat, 'rc' => $rc));
}
killme();
exit;
}
// change to switch structure?
// account block/unblock button was submitted
if (x($_POST, 'page_accounts_block')) {
@@ -55,7 +146,7 @@ class Accounts {
account_deny($hash);
}
}
goaway(z_root() . '/admin/accounts' );
}
@@ -75,19 +166,21 @@ class Accounts {
$account = q("SELECT * FROM account WHERE account_id = %d",
intval($uid)
);
if (! $account) {
notice( t('Account not found') . EOL);
goaway(z_root() . '/admin/accounts' );
}
check_form_security_token_redirectOnErr('/admin/accounts', 'admin_accounts', 't');
$debug = '';
switch (argv(2)){
case 'delete':
// delete user
account_remove($uid,true,false);
notice( sprintf(t("Account '%s' deleted"), $account[0]['account_email']) . EOL);
break;
case 'block':
@@ -95,7 +188,7 @@ class Accounts {
intval(ACCOUNT_BLOCKED),
intval($uid)
);
notice( sprintf( t("Account '%s' blocked") , $account[0]['account_email']) . EOL);
break;
case 'unblock':
@@ -103,27 +196,74 @@ class Accounts {
intval(ACCOUNT_BLOCKED),
intval($uid)
);
notice( sprintf( t("Account '%s' unblocked"), $account[0]['account_email']) . EOL);
break;
}
goaway(z_root() . '/admin/accounts' );
}
/* get pending */
$pending = q("SELECT account.*, register.hash from account left join register on account_id = register.uid where (account_flags & %d )>0 ",
intval(ACCOUNT_PENDING)
);
$tao = 'tao.zar.zarax = ' . "'" . '<img src="' . z_root() . '/images/zapax16.gif">' . "';\n";
// by default we will only return verified results. if reg_all is set we will return everything''
$get_all = isset($_REQUEST['get_all']);
$pending = get_pending_accounts($get_all);
unset($_SESSION[self::MYP]);
if ($pending) {
// collect and group all ip
$atips = dbq("SELECT reg_atip AS atip, COUNT(reg_atip) AS atips FROM register
WHERE reg_vital = 1 GROUP BY reg_atip"
);
(($atips) ? $atipn = array_column($atips, 'atips', 'atip') : $atipn = ['' => 0]);
$tao .= 'tao.zar.zarar = {';
foreach ($pending as $n => $v) {
$stuff = json_decode($v['reg_stuff'], true);
if(isset($stuff['msg'])) {
$pending[$n]['msg'] = $stuff['msg'];
}
if (array_key_exists($v['reg_atip'], $atipn)) {
$pending[$n]['reg_atip'] = $v['reg_atip'];
$pending[$n]['reg_atip_n'] = $atipn[$v['reg_atip']];
}
$pending[$n]['status'] = '';
if($pending[$n]['reg_flags'] & ACCOUNT_UNVERIFIED > 0)
$pending[$n]['status'] = [t('Unverified'), 'bg-warning'];
if($pending[$n]['status'] && $pending[$n]['reg_expires'] < datetime_convert())
$pending[$n]['status'] = [t('Expired'), 'bg-danger text-white'];
// timezone adjust date_time for display
$pending[$n]['reg_created'] = datetime_convert('UTC', date_default_timezone_get(), $pending[$n]['reg_created']);
$pending[$n]['reg_startup'] = datetime_convert('UTC', date_default_timezone_get(), $pending[$n]['reg_startup']);
$pending[$n]['reg_expires'] = datetime_convert('UTC', date_default_timezone_get(), $pending[$n]['reg_expires']);
// better secure
$tao .= $n . ": '" . substr(bin2hex($v['reg_hash']),0,8) . "',";
$_SESSION[self::MYP]['h'][] = substr($v['reg_hash'],0,4);
$_SESSION[self::MYP]['i'][] = $v['reg_id'];
}
$tao = rtrim($tao,',') . '};' . "\n";
}
// <- hilmar]
/* get accounts */
$total = q("SELECT count(*) as total FROM account");
if (count($total)) {
\App::set_pager_total($total[0]['total']);
\App::set_pager_itemspage(100);
}
$serviceclass = (($_REQUEST['class']) ? " and account_service_class = '" . dbesc($_REQUEST['class']) . "' " : '');
$key = (($_REQUEST['key']) ? dbesc($_REQUEST['key']) : 'account_id');
@@ -134,8 +274,8 @@ class Accounts {
$base = z_root() . '/admin/accounts?f=';
$odir = (($dir === 'asc') ? '0' : '1');
$users = q("SELECT account_id , account_email, account_lastlog, account_created, account_expires, account_service_class, ( account_flags & %d ) > 0 as blocked,
(SELECT %s FROM channel as ch WHERE ch.channel_account_id = ac.account_id and ch.channel_removed = 0 ) as channels FROM account as ac
$users = q("SELECT account_id , account_email, account_lastlog, account_created, account_expires, account_service_class, ( account_flags & %d ) > 0 as blocked,
(SELECT %s FROM channel as ch WHERE ch.channel_account_id = ac.account_id and ch.channel_removed = 0 ) as channels FROM account as ac
where true $serviceclass and account_flags != %d order by $key $dir limit %d offset %d ",
intval(ACCOUNT_BLOCKED),
db_concat('ch.channel_address', ' '),
@@ -143,15 +283,15 @@ class Accounts {
intval(\App::$pager['itemspage']),
intval(\App::$pager['start'])
);
// function _setup_users($e){
// $accounts = Array(
// t('Normal Account'),
// t('Normal Account'),
// t('Soapbox Account'),
// t('Community/Celebrity Account'),
// t('Automatic Friend Account')
// );
// $e['page_flags'] = $accounts[$e['page-flags']];
// $e['register_date'] = relative_date($e['register_date']);
// $e['login_date'] = relative_date($e['login_date']);
@@ -159,49 +299,57 @@ class Accounts {
// return $e;
// }
// $users = array_map("_setup_users", $users);
$t = get_markup_template('admin_accounts.tpl');
$o = replace_macros($t, array(
// strings //
'$debug' => $debug,
'$title' => t('Administration'),
'$page' => t('Accounts'),
'$submit' => t('Submit'),
'$select_all' => t('select all'),
'$h_pending' => t('Registrations waiting for confirm'),
'$th_pending' => array( t('Request date'), t('Email') ),
'$no_pending' => t('No registrations.'),
'$get_all' => (($get_all) ? t('Show verified registrations') : t('Show all registrations')),
'$get_all_link' => (($get_all) ? z_root() .'/admin/accounts' : z_root() .'/admin/accounts?get_all'),
'$sel_tall' => t('Select toggle'),
'$sel_deny' => t('Deny selected'),
'$sel_aprv' => t('Approve selected'),
'$h_pending' => (($get_all) ? t('All registrations') : t('Verified registrations waiting for approval')),
'$th_pending' => array(t('Request date'), 'dId2', t('Email'), 'IP', t('Requests')),
'$no_pending' => (($get_all) ? t('No registrations available') : t('No verified registrations available')),
'$approve' => t('Approve'),
'$deny' => t('Deny'),
'$delete' => t('Delete'),
'$block' => t('Block'),
'$unblock' => t('Unblock'),
'$verified' => t('Verified'),
'$not_verified' => t('Not yet verified'),
'$odir' => $odir,
'$base' => $base,
'$h_users' => t('Accounts'),
'$th_users' => array(
'$th_users' => array(
[ t('ID'), 'account_id' ],
[ t('Email'), 'account_email' ],
[ t('All Channels'), 'channels' ],
[ t('All channels'), 'channels' ],
[ t('Register date'), 'account_created' ],
[ t('Last login'), 'account_lastlog' ],
[ t('Expires'), 'account_expires' ],
[ t('Service Class'), 'account_service_class'] ),
'$confirm_delete_multi' => t('Selected accounts will be deleted!\n\nEverything these accounts had posted on this site will be permanently deleted!\n\nAre you sure?'),
'$confirm_delete' => t('The account {0} will be deleted!\n\nEverything this account has posted on this site will be permanently deleted!\n\nAre you sure?'),
[ t('Service class'), 'account_service_class'] ),
'$confirm_delete_multi' => p2j(t('Selected accounts will be deleted!\n\nEverything these accounts had posted on this site will be permanently deleted!\n\nAre you sure?')),
'$confirm_delete' => p2j(t('The account {0} will be deleted!\n\nEverything this account has posted on this site will be permanently deleted!\n\nAre you sure?')),
'$form_security_token' => get_form_security_token("admin_accounts"),
// values //
'$baseurl' => z_root(),
'$pending' => $pending,
'$users' => $users,
'$baseurl' => z_root(),
'$tao' => $tao,
'$pending' => $pending,
'$users' => $users,
'$msg' => t('Message')
));
$o .= paginate($a);
return $o;
}
}

View File

@@ -173,4 +173,4 @@ class Channels {
return $o;
}
}
}

View File

@@ -5,14 +5,25 @@ namespace Zotlabs\Module\Admin;
class Site {
/**
* @brief POST handler for Admin Site Page.
*
*/
function post(){
// [hilmar->
$this->isajax = is_ajax();
$this->eol = $this->isajax ? "\n" : EOL;
// ]
if (!x($_POST, 'page_site')) {
return;
// [
if (!$this->isajax)
// ]
return;
}
// [
$this->msgbg = '';
// <-hilmar]
check_form_security_token_redirectOnErr('/admin/site', 'admin_site');
@@ -24,14 +35,17 @@ class Site {
$siteinfo = ((x($_POST,'siteinfo')) ? trim($_POST['siteinfo']) : '');
$language = ((x($_POST,'language')) ? notags(trim($_POST['language'])) : '');
$theme = ((x($_POST,'theme')) ? notags(trim($_POST['theme'])) : '');
// $theme_mobile = ((x($_POST,'theme_mobile')) ? notags(trim($_POST['theme_mobile'])) : '');
// $site_channel = ((x($_POST,'site_channel')) ? notags(trim($_POST['site_channel'])) : '');
// $theme_mobile = ((x($_POST,'theme_mobile')) ? notags(trim($_POST['theme_mobile'])) : '');
// $site_channel = ((x($_POST,'site_channel')) ? notags(trim($_POST['site_channel'])) : '');
$maximagesize = ((x($_POST,'maximagesize')) ? intval(trim($_POST['maximagesize'])) : 0);
$register_policy = ((x($_POST,'register_policy')) ? intval(trim($_POST['register_policy'])) : 0);
$register_wo_email = ((x($_POST,'register_wo_email')) ? intval(trim($_POST['register_wo_email'])) : 0);
$minimum_age = ((x($_POST,'minimum_age')) ? intval(trim($_POST['minimum_age'])) : 13);
$access_policy = ((x($_POST,'access_policy')) ? intval(trim($_POST['access_policy'])) : 0);
$invite_only = ((x($_POST,'invite_only')) ? True : False);
$reg_autochannel = ((x($_POST,'auto_channel_create')) ? True : False);
$invitation_only = ((x($_POST,'invitation_only')) ? True : False);
$invitation_also = ((x($_POST,'invitation_also')) ? True : False);
$abandon_days = ((x($_POST,'abandon_days')) ? intval(trim($_POST['abandon_days'])) : 0);
$register_text = ((x($_POST,'register_text')) ? notags(trim($_POST['register_text'])) : '');
@@ -75,6 +89,16 @@ class Site {
$maxloadavg = ((x($_POST,'maxloadavg')) ? intval(trim($_POST['maxloadavg'])) : 50);
$feed_contacts = ((x($_POST,'feed_contacts')) ? intval($_POST['feed_contacts']) : 0);
$verify_email = ((x($_POST,'verify_email')) ? 1 : 0);
$register_perday = ((x($_POST,'register_perday')) ? intval(trim($_POST['register_perday'])) : 50);
$register_sameip = ((x($_POST,'register_sameip')) ? intval(trim($_POST['register_sameip'])) : 3);
$regdelayn = ((x($_POST,'zardelayn')) ? intval(trim($_POST['zardelayn'])) : 0);
$regdelayu = ((x($_POST,'zardelay')) ? notags(trim($_POST['zardelay'])) : '');
$reg_delay = (preg_match('/^[a-z]{1,1}$/', $regdelayu) ? $regdelayn . $regdelayu : '');
$regexpiren = ((x($_POST,'zarexpiren')) ? intval(trim($_POST['zarexpiren'])) : 0);
$regexpireu = ((x($_POST,'zarexpire')) ? notags(trim($_POST['zarexpire'])) : '');
$reg_expire = (preg_match('/^[a-z]{1,1}$/', $regexpireu) ? $regexpiren . $regexpireu : '');
$imagick_path = ((x($_POST,'imagick_path')) ? trim($_POST['imagick_path']) : '');
$force_queue = ((intval($_POST['force_queue']) > 0) ? intval($_POST['force_queue']) : 3000);
$pub_incl = escape_tags(trim($_POST['pub_incl']));
@@ -82,6 +106,35 @@ class Site {
$permissions_role = escape_tags(trim($_POST['permissions_role']));
// [hilmar->
$this->register_duty = ((x($_POST,'register_duty')) ? notags(trim($_POST['register_duty'])) : '');
if (! preg_match('/^[0-9 .,:\-]{0,191}$/', $this->register_duty)) {
$this->msgbg .= 'ZAR0131E,' . t('Invalid input') . $this->eol;
$this->error++;
} else {
$this->duty();
if ($this->isajax) {
echo json_encode(array('msgbg' => $this->msgbg, 'me' => 'zar'));
// that mission is complete
killme();
exit;
} else {
//logger( print_r( $this->msgbg, true) );
//logger( print_r( $this->joo, true) );
if ($this->error === 0) {
set_config('system', 'register_duty', $this->register_duty);
set_config('system', 'register_duty_jso', $this->joo);
} else {
notice('ZAR0130E,'.t('Errors') . ': ' . $this->error) . EOL . $this->msgfg;
}
}
}
// <-hilmar]
set_config('system', 'feed_contacts', $feed_contacts);
set_config('system', 'delivery_interval', $delivery_interval);
set_config('system', 'delivery_batch_count', $delivery_batch_count);
@@ -96,6 +149,10 @@ class Site {
set_config('system', 'login_on_homepage', $login_on_homepage);
set_config('system', 'enable_context_help', $enable_context_help);
set_config('system', 'verify_email', $verify_email);
set_config('system', 'max_daily_registrations', $register_perday);
set_config('system', 'register_sameip', $register_sameip);
set_config('system', 'register_delay', $reg_delay);
set_config('system', 'register_expire', $reg_expire);
set_config('system', 'default_expire_days', $default_expire_days);
set_config('system', 'active_expire_days', $active_expire_days);
set_config('system', 'reply_address', $reply_address);
@@ -126,17 +183,20 @@ class Site {
set_config('system','siteinfo',$siteinfo);
set_config('system', 'language', $language);
set_config('system', 'theme', $theme);
// if ( $theme_mobile === '---' ) {
// del_config('system', 'mobile_theme');
// } else {
// set_config('system', 'mobile_theme', $theme_mobile);
// }
// set_config('system','site_channel', $site_channel);
// if ( $theme_mobile === '---' ) {
// del_config('system', 'mobile_theme');
// } else {
// set_config('system', 'mobile_theme', $theme_mobile);
// }
// set_config('system','site_channel', $site_channel);
set_config('system','maximagesize', $maximagesize);
set_config('system','register_policy', $register_policy);
set_config('system','register_wo_email', $register_wo_email);
set_config('system','minimum_age', $minimum_age);
set_config('system','invitation_only', $invite_only);
set_config('system','auto_channel_create', $reg_autochannel);
set_config('system', 'invitation_only', $invitation_only);
set_config('system', 'invitation_also', $invitation_also);
set_config('system','access_policy', $access_policy);
set_config('system','account_abandon_days', $abandon_days);
set_config('system','register_text', $register_text);
@@ -260,6 +320,8 @@ class Site {
REGISTER_APPROVE => t("Yes - with approval"),
REGISTER_OPEN => t("Yes")
);
$this->register_duty = get_config('system', 'register_duty', '-:-');
$register_perday = get_config('system','max_daily_registrations', 50);
/* Acess policy */
$access_choices = Array(
@@ -286,9 +348,66 @@ class Site {
$homelogin = get_config('system','login_on_homepage');
$enable_context_help = get_config('system','enable_context_help');
// for reuse reg_delay and reg_expire
$reg_rabots = array(
'i' => t('Minute(s)'),
'h' => t('Hour(s)') ,
'd' => t('Day(s)') ,
'w' => t('Week(s)') ,
'm' => t('Month(s)') ,
'y' => t('Year(s)')
);
$regdelay_n = $regdelay_u = false;
$regdelay = get_config('system','register_delay');
if ($regdelay)
list($regdelay_n, $regdelay_u) = array(substr($regdelay,0,-1),substr($regdelay,-1));
$reg_delay = replace_macros(get_markup_template('field_duration.qmc.tpl'),
array(
'label' => t('Register verification delay'),
'qmc' => 'zar',
'qmcid' => '',
'help' => t('Time to wait before a registration can be verified'),
'field' => array(
'name' => 'delay',
'title' => t('duration up from now'),
'value' => ($regdelay_n === false ? 0 : $regdelay_n),
'min' => '0',
'max' => '99',
'size' => '2',
'default' => ($regdelay_u === false ? 'i' : $regdelay_u)
),
'rabot' => $reg_rabots
)
);
$regexpire_n = $regexpire_u = false;
$regexpire = get_config('system','register_expire');
if ($regexpire)
list($regexpire_n, $regexpire_u) = array(substr($regexpire,0,-1),substr($regexpire,-1));
$reg_expire = replace_macros(get_markup_template('field_duration.qmc.tpl'),
array(
'label' => t('Register verification expiration time'),
'qmc' => 'zar',
'qmcid' => '',
'help' => t('Time before an unverified registration will expire'),
'field' => array(
'name' => 'expire',
'title' => t('duration up from now'),
'value' => ($regexpire_n === false ? 3 : $regexpire_n),
'min' => '0',
'max' => '99',
'size' => '2',
'default' => ($regexpire_u === false ? 'd' : $regexpire_u)
),
'rabot' => $reg_rabots
)
);
$tao = '';
$t = get_markup_template("admin_site.tpl");
return replace_macros($t, array(
'$title' => t('Administration'),
// interfacing js vars
'$tao' => $tao,
'$page' => t('Site'),
'$submit' => t('Submit'),
'$registration' => t('Registration'),
@@ -305,21 +424,87 @@ class Site {
'$siteinfo' => array('siteinfo', t('Site Information'), get_config('system','siteinfo'), t("Publicly visible description of this site. Displayed on siteinfo page. BBCode can be used here")),
'$language' => array('language', t("System language"), get_config('system','language'), "", $lang_choices),
'$theme' => array('theme', t("System theme"), get_config('system','theme'), t("Default system theme - may be over-ridden by user profiles - <a href='#' id='cnftheme'>change theme settings</a>"), $theme_choices),
// '$theme_mobile' => array('theme_mobile', t("Mobile system theme"), get_config('system','mobile_theme'), t("Theme for mobile devices"), $theme_choices_mobile),
// '$site_channel' => array('site_channel', t("Channel to use for this website's static pages"), get_config('system','site_channel'), t("Site Channel")),
// '$theme_mobile' => array('theme_mobile', t("Mobile system theme"), get_config('system','mobile_theme'), t("Theme for mobile devices"), $theme_choices_mobile),
// '$site_channel' => array('site_channel', t("Channel to use for this website's static pages"), get_config('system','site_channel'), t("Site Channel")),
'$feed_contacts' => array('feed_contacts', t('Allow Feeds as Connections'),get_config('system','feed_contacts'),t('(Heavy system resource usage)')),
'$maximagesize' => array('maximagesize', t("Maximum image size"), intval(get_config('system','maximagesize')), t("Maximum size in bytes of uploaded images. Default is 0, which means no limits.")),
'$register_policy' => array('register_policy', t("Does this site allow new member registration?"), get_config('system','register_policy'), "", $register_choices),
'$invite_only' => array('invite_only', t("Invitation only"), get_config('system','invitation_only'), t("Only allow new member registrations with an invitation code. Above register policy must be set to Yes.")),
'$minimum_age' => array('minimum_age', t("Minimum age"), (x(get_config('system','minimum_age'))?get_config('system','minimum_age'):13), t("Minimum age (in years) for who may register on this site.")),
'$access_policy' => array('access_policy', t("Which best describes the types of account offered by this hub?"), get_config('system','access_policy'), t("This is displayed on the public server site list."), $access_choices),
'$register_text' => array('register_text', t("Register text"), htmlspecialchars(get_config('system','register_text'), ENT_QUOTES, 'UTF-8'), t("Will be displayed prominently on the registration page.")),
// Register
// [hilmar->
'$register_text' => [
'register_text',
t("Register text"),
htmlspecialchars(get_config('system','register_text'), ENT_QUOTES, 'UTF-8'),
t("This text will be displayed prominently at the registration page")
],
'$register_policy' => [
'register_policy',
t("Does this site allow new member registration?"),
get_config('system','register_policy'),
"",
$register_choices,
],
'$register_duty' => [
'register_duty',
t('Configure the registration open days/hours'),
get_config('system', 'register_duty', '-:-'),
t('Empty or \'-:-\' value will keep registration open 24/7 (default)') . EOL .
t('Weekdays and hours must be separated by colon \':\', From-To ranges with a dash `-` example: 1:800-1200') . EOL .
t('Weekday:Hour pairs must be separated by space \' \' example: 1:900-1700 2:900-1700') . EOL .
t('From-To ranges must be separated by comma \',\' example: 1:800-1200,1300-1700 or 1-2,4-5:900-1700') . EOL .
t('Advanced examples:') . ' 1-5:0900-1200,1300-1700 6:900-1230 ' . t('or') . ' 1-2,4-5:800-1800<br>' . EOL .
'<a id="zar083a" class="btn btn-sm btn-outline-secondary zuia">' . t('Check your configuration') . '</a>'. EOL
],
'$register_perday' => [
'register_perday',
t('Max account registrations per day'),
get_config('system', 'max_daily_registrations', 50),
t('Unlimited if zero or no value - default 50')
],
'$register_sameip' => [
'register_sameip',
t('Max account registrations from same IP'),
get_config('system', 'register_sameip', 3),
t('Unlimited if zero or no value - default 3')
],
'$reg_delay' => $reg_delay,
'$reg_expire' => $reg_expire,
'$reg_autochannel' => [
'auto_channel_create',
t("Auto channel create"),
get_config('system','auto_channel_create', 1),
t("If disabled the channel will be created in a separate step during the registration process")
],
'$invitation_only' => [
'invitation_only',
t("Require invite code"),
$invitation_only
],
'$invitation_also' => [
'invitation_also',
t("Allow invite code"),
$invitation_also
],
'$verify_email' => [
'verify_email',
t("Require email address"),
get_config('system','verify_email'),
t("The provided email address will be verified (recommended)")
],
'$abandon_days' => [
'abandon_days',
t('Abandon account after x days'),
get_config('system','account_abandon_days'),
t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.')
],
// <-hilmar]
'$role' => $role,
'$frontpage' => array('frontpage', t("Site homepage to show visitors (default: login box)"), get_config('system','frontpage'), t("example: 'pubstream' to show public stream, 'page/sys/home' to show a system webpage called 'home' or 'include:home.html' to include a file.")),
'$mirror_frontpage' => array('mirror_frontpage', t("Preserve site homepage URL"), get_config('system','mirror_frontpage'), t('Present the site homepage in a frame at the original location instead of redirecting')),
'$abandon_days' => array('abandon_days', t('Accounts abandoned after x days'), get_config('system','account_abandon_days'), t('Will not waste system resources polling external sites for abandonded accounts. Enter 0 for no time limit.')),
'$allowed_sites' => array('allowed_sites', t("Allowed friend domains"), get_config('system','allowed_sites'), t("Comma separated list of domains which are allowed to establish friendships with this site. Wildcards are accepted. Empty to allow any domains")),
'$verify_email' => array('verify_email', t("Verify Email Addresses"), get_config('system','verify_email'), t("Check to verify email addresses used in account registration (recommended).")),
'$force_publish' => array('publish_all', t("Force publish"), get_config('system','publish_all'), t("Check to force all profiles on this site to be listed in the site directory.")),
'$disable_discover_tab' => array('disable_discover_tab', t('Import Public Streams'), $discover_tab, t('Import and allow access to public content pulled from other sites. Warning: this content is unmoderated.')),
'$site_firehose' => array('site_firehose', t('Site only Public Streams'), get_config('system','site_firehose'), t('Allow access to public content originating only from this site if Imported Public Streams are disabled.')),
@@ -350,15 +535,184 @@ class Site {
'$maxloadavg' => array('maxloadavg', t("Maximum Load Average"), ((intval(get_config('system','maxloadavg')) > 0)?get_config('system','maxloadavg'):50), t("Maximum system load before delivery and poll processes are deferred - default 50.")),
'$default_expire_days' => array('default_expire_days', t('Expiration period in days for imported (grid/network) content'), intval(get_config('system','default_expire_days')), t('0 for no expiration of imported content')),
'$active_expire_days' => array('active_expire_days', t('Do not expire any posts which have comments less than this many days ago'), intval(get_config('system','active_expire_days',7)), ''),
'$sellpage' => array('site_sellpage', t('Public servers: Optional landing (marketing) webpage for new registrants'), get_config('system','sellpage',''), sprintf( t('Create this page first. Default is %s/register'),z_root())),
'$first_page' => array('first_page', t('Page to display after creating a new channel'), get_config('system','workflow_channel_next','profiles'), t('Default: profiles')),
'$location' => array('site_location', t('Optional: site location'), get_config('system','site_location',''), t('Region or country')),
'$form_security_token' => get_form_security_token("admin_site"),
));
}
/**
* @brief Admin page site common post submit and ajax interaction
* @author hilmar runge
* @since 2020-02-04
* Configure register office duty weekdays and hours
* Syntax: weekdays:hours [weekdays:hours]
* [.d[,d-d.]]]:hhmm-hhmm[,hhmm-hhmm...]
* ranges are between blanks, days are 1-7, where 1 = Monday
* hours are [h]hmm 3-4digit 24 clock values
* ie 0900-1200,1300-1800 for hours
* ie 1-2,4,5 for weekdays
* ie 1-2:900-1800 monday and tuesday open from 9 to 18h
*
* @var $register_duty is the input field from the admin -> site page
* @return the results are in the class vars $error, $msgbg and $jsoo
* $jsoo is
*/
// 3-4 digit 24h clock regex
const regxTime34 = '/^(?:2[0-3]|[01][0-9]|[0-9])[0-5][0-9]$/';
var $wdconst = array('','mo','tu','we','th','fr','sa','so');
// in
var $register_duty;
// intermediate
var $isajax;
// return
var $jsoo;
var $msgbg;
var $error = 0;
var $msgfg = '';
private function duty() {
$aro=array_fill(1, 7, 0);
if ($this->isajax) {
$op = (preg_match('/[a-z]{2,4}/', $_REQUEST['zarop'])) ? $_REQUEST['zarop'] : '';
if ($op == 'zar083') {
$this->msgbg = 'Testmode:' . $this->eol . $this->msgbg;
} else {
killme();
exit;
}
}
$ranges = preg_split('/\s+/', $this->register_duty);
$this->msgbg .= '..ranges: ' . print_r(count($ranges),true) . $this->eol;
foreach ($ranges as $rn => $range) {
list($ws,$hs,) = explode(':', $range);
$ws ? $arw = explode( ',', $ws) : $arw=array();
$this->msgbg .= ($rn+1).'.weekday ranges: ' . count($arw) . $this->eol;
// $this->msgbg .= print_r($arw,true);
$hs ? $arh = explode( ',', $hs) : $arh=array();
$this->msgbg .= ($rn+1).'.hour ranges: ' . count($arh) . $this->eol;
$this->msgbg .= ($rn+1).'.wdays: ' . ( $ws ? print_r($ws,true) : 'none') . ' : '
. ' hours: ' . print_r($hs,true) . $this->eol;
// several hs may belog to one wd
// aro[0] is tmp store
foreach ($arh as $hs) {
list($ho,$hc,) = explode( '-', $hs );
// no value forces open very early, and be sure having valid hhmm values
!$ho ? $ho = "0000" : '';
!$hc ? $hc = "0000" : ''; // pseudo
if (preg_match(self::regxTime34, $ho)
&& preg_match(self::regxTime34, $hc)) {
// fix pseudo, allow no reverse range
$hc == "0000" || $ho > $hc ? $hc = "2400" : '';
$aro[0][$ho] = 0;
$aro[0][$hc] = 1;
$this->msgbg .= ($ho ? ' .open:' . $ho : '') . ($hc ? ' close:' . $hc : '') .$this->eol;
} else {
$this->msgbg .= ' .' . t('Invalid 24h time value (hhmm/hmm)') . $this->eol;
$this->msgfg .= ' .ZAR0132E,' . t('Invalid 24h time value (hhmm/hmm)') . $this->eol;
$this->error++;
}
}
// the weekday(s) values or ranges
foreach ($arw as $ds) {
$wd=explode('-', $ds);
array_key_exists("1", $wd) && $wd[1]=="" ? $wd[1] = "7" : ''; // a case 3-
array_key_exists("1", $wd) && $wd[0]=="" ? $wd[0] = "1" : ''; // a case -3
!array_key_exists("1", $wd) ? $wd[1] = $wd[0] : ''; // a case 3
if ($wd[0] > $wd[1]) continue; // reverse order will be ignored // a case 5-3
if (preg_match('/^[1-7]{1}$/', $wd[0])) {
if (preg_match('/^[1-7]{1}$/', $wd[1])) {
// $this->msgbg .= print_r($wd,true);
for ($i=$wd[0]; $i<=$wd[1]; $i++) {
// take the tmp store for the selected day(s)
$aro[$i]=$aro[0];
}
}
}
}
//$this->msgbg .= 'aro0: ' . print_r($aro,true) . $this->eol; // 4devels
// clear the tmp store
$aro[0]=array();
}
// discart the tmp store
unset($aro[0]);
// not configured days close at the beginning 0000h
for ($i=1;$i<=7;$i++) { is_array($aro[$i]) ? '' : $aro[$i] = array("0000" => 1); }
// $this->msgbg .= 'aro: ' . print_r($aro,true) . $this->eol; // 4devels
if ($this->isajax) {
// tell what we have
// $this->msgbg .= 'aro0: ' . print_r($aro,true) . $this->eol; // 4devels
$this->msgbg .= 'Duty time table:' . $this->eol;
foreach ($aro as $dow => $hrs) {
$this->msgbg .= ' ' . $this->wdconst[$dow] . ' ';
// $this->msgbg .= '**' . print_r($hrs,true);
foreach ($hrs as $h => $o) {
$this->msgbg .= ((!$o) ? $h . ':open' : $h . ':close') . ', ';
}
$this->msgbg = rtrim($this->msgbg, ', ') . $this->eol;
}
$this->msgbg .= 'Generating 6 random times to check duty hours: ' . $this->eol;
// we only need some random dates from anyway in past or future
// because only the weekday and the clock is to test
for ($i=0; $i<6; $i++) {
$adow = rand(1, 7); // 1 to 7 (days)
$cdow = $this->wdconst[$adow];
// below is the essential algo to verify a date (of format Hi) meets an open or closed condition
$t = date('Hi', ( rand(time(), 60*60*24+time()) ) );
$how='close';
foreach ($aro[$adow] as $o => $v) {
// $this->msgbg .= 'debug: ' . $o . ' gt ' . $t . ' / ' . $v . $this->eol; // 4devels
if ($o > $t) {
$how = ($v ? 'open' : 'close');
break;
}
}
// now we know
$this->msgbg .= ' ' . $cdow . '.' . $t . '=' . $how . ', ';
}
$this->msgbg = rtrim($this->msgbg, ', ') . $this->eol;
}
/*
//$jov1 = array( 'view1' => $aro, 'view2' => '');
$jov2=array();
foreach ($aro as $d => $ts) {
foreach ($ts as $t => $ft) {
$jov2['view2'][$ft][] = $d.$t;
//$ft=="1" && $t=="0000" ? $jov2['view2']["0"][] = $d."2400" : '';
}
}
$this->msgbg .= print_r($jov2, true) . $this->eol; // 4devels
*/
$this->joo = json_encode($aro);
// $this->msgbg .= $this->joo . $this->eol; // 4devels
// $this->msgbg .= print_r($aro, true) . $this->eol; // 4devels
$okko = (json_decode($this->joo, true) ? true : false);
if (!$okko) {
$this->msgbg .= 'ZAR0139D,json 4 duty KO crash' . $this->eol;
$this->msgfg .= 'ZAR0139D,json 4 duty KO crash' . $this->eol;
$this->error++;
}
return ;
}
}

View File

@@ -16,8 +16,8 @@ class Bookmarks extends \Zotlabs\Web\Controller {
nav_set_selected('Bookmarks');
$item_id = intval($_REQUEST['item']);
$burl = trim($_REQUEST['burl']);
$item_id = (isset($_REQUEST['item']) ? $_REQUEST['item'] : false);
$burl = (isset($_REQUEST['burl']) ? trim($_REQUEST['burl']) : '');
if(! $item_id)
return;
@@ -38,7 +38,7 @@ class Bookmarks extends \Zotlabs\Web\Controller {
$item = $i[0];
$terms = get_terms_oftype($item['term'],TERM_BOOKMARK);
$terms = (x($item, 'term') ? get_terms_oftype($item['term'],TERM_BOOKMARK) : false);
if($terms) {
require_once('include/bookmarks.php');

View File

@@ -19,45 +19,45 @@ class Cal extends Controller {
if(observer_prohibited()) {
return;
}
if(argc() > 1) {
$nick = argv(1);
profile_load($nick);
$channelx = channelx_by_nick($nick);
if(! $channelx) {
notice( t('Channel not found.') . EOL);
return;
}
App::$data['channel'] = $channelx;
$observer = App::get_observer();
App::$data['observer'] = $observer;
head_set_icon(App::$data['channel']['xchan_photo_s']);
App::$page['htmlhead'] .= "<script> var profile_uid = " . ((App::$data['channel']) ? App::$data['channel']['channel_id'] : 0) . "; </script>" ;
}
return;
}
function get() {
if(observer_prohibited()) {
return;
}
$channel = App::$data['channel'];
// since we don't currently have an event permission - use the stream permission
if(! perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_stream')) {
notice( t('Permissions denied.') . EOL);
return;
@@ -76,10 +76,10 @@ class Cal extends Controller {
if(! perm_is_allowed($channel['channel_id'], get_observer_hash(), 'view_contacts') || App::$profile['hide_friends'])
$sql_extra .= " and etype != 'birthday' ";
$first_day = feature_enabled($channel['channel_id'], 'cal_first_day');
$first_day = (($first_day) ? $first_day : 0);
$start = '';
$finish = '';
@@ -87,7 +87,7 @@ class Cal extends Controller {
if (x($_GET,'start')) $start = $_GET['start'];
if (x($_GET,'end')) $finish = $_GET['end'];
}
$start = datetime_convert('UTC','UTC',$start);
$finish = datetime_convert('UTC','UTC',$finish);
$adjust_start = datetime_convert('UTC', date_default_timezone_get(), $start);
@@ -107,10 +107,10 @@ class Cal extends Controller {
// Noting this for now - it will need to be fixed here and in Friendica.
// Ultimately the finish date shouldn't be involved in the query.
$r = q("SELECT event.*, item.plink, item.item_flags, item.author_xchan, item.owner_xchan, item.id as item_id
from event left join item on event.event_hash = item.resource_id
where item.resource_type = 'event' and event.uid = %d and event.uid = item.uid
AND (( event.adjust = 0 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )
OR ( event.adjust = 1 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' ))
from event left join item on event.event_hash = item.resource_id
where item.resource_type = 'event' and event.uid = %d and event.uid = item.uid
AND (( event.adjust = 0 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' )
OR ( event.adjust = 1 AND ( event.dtend >= '%s' or event.nofinish = 1 ) AND event.dtstart <= '%s' ))
$sql_extra",
intval($channel['channel_id']),
dbesc($start),
@@ -119,7 +119,7 @@ class Cal extends Controller {
dbesc($adjust_finish)
);
}
if($r) {
xchan_query($r);
$r = fetch_post_tags($r,true);
@@ -127,20 +127,16 @@ class Cal extends Controller {
}
$events = [];
if($r) {
foreach($r as $rr) {
$tz = get_iconfig($rr, 'event', 'timezone');
if(! $tz)
$tz = 'UTC';
$start = (($rr['adjust']) ? datetime_convert($tz, date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c'));
$start = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtstart'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtstart'], 'c'));
if ($rr['nofinish']){
$end = null;
} else {
$end = (($rr['adjust']) ? datetime_convert($tz, date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'));
$end = (($rr['adjust']) ? datetime_convert('UTC', date_default_timezone_get(), $rr['dtend'], 'c') : datetime_convert('UTC', 'UTC', $rr['dtend'], 'c'));
}
$html = '';
@@ -149,6 +145,10 @@ class Cal extends Controller {
$html = format_event_html($rr);
}
$tz = get_iconfig($rr, 'event', 'timezone');
if(! $tz)
$tz = 'UTC';
$events[] = array(
'calendar_id' => 'channel_calendar',
'rw' => true,
@@ -178,7 +178,7 @@ class Cal extends Controller {
echo json_encode($events);
killme();
}
if (x($_GET,'id')) {
$o = replace_macros(get_markup_template("cal_event.tpl"), [
'$events' => $events
@@ -210,7 +210,7 @@ class Cal extends Controller {
]);
return $o;
}
}

View File

@@ -135,7 +135,7 @@ class Cdav extends Controller {
$auth = new \Zotlabs\Storage\BasicAuth();
$auth->setRealm(ucfirst(\Zotlabs\Lib\System::get_platform_name()) . 'CalDAV/CardDAV');
if (local_channel()) {
if(local_channel()) {
logger('loggedin');
@@ -153,9 +153,9 @@ class Cdav extends Controller {
$auth->observer = $channel['channel_hash'];
$principalUri = 'principals/' . $channel['channel_address'];
if(!cdav_principal($principalUri)) {
if(! cdav_principal($principalUri)) {
$this->activate($pdo, $channel);
if(!cdav_principal($principalUri)) {
if(! cdav_principal($principalUri)) {
return;
}
}
@@ -168,21 +168,24 @@ class Cdav extends Controller {
if($httpmethod === 'PUT' || $httpmethod === 'DELETE') {
$channel = channelx_by_nick(argv(2));
$principalUri = 'principals/' . $channel['channel_address'];
$httpuri = $_SERVER['REQUEST_URI'];
logger("debug: method: " . $httpmethod, LOGGER_DEBUG);
logger("debug: uri: " . $httpuri, LOGGER_DEBUG);
if(strpos($httpuri, 'cdav/addressbooks')) {
if(strpos($httpuri, 'cdav/addressbooks') !== false) {
$sync = 'addressbook';
$cdavtable = 'addressbooks';
}
elseif(strpos($httpuri, 'cdav/calendars')) {
elseif(strpos($httpuri, 'cdav/calendars') !== false) {
$sync = 'calendar';
$cdavtable = 'calendarinstances';
}
else
else {
$sync = false;
}
if($sync) {
@@ -191,14 +194,13 @@ class Cdav extends Controller {
logger("debug: body: " . $httpbody, LOGGER_DEBUG);
if($x = get_cdav_id($principalUri, explode("/", $httpuri)[4], $cdavtable)) {
if($x = get_cdav_id($principalUri, argv(3), $cdavtable)) {
$cdavdata = $this->get_cdav_data($x['id'], $cdavtable);
$etag = (isset($_SERVER['HTTP_IF_MATCH']) ? $_SERVER['HTTP_IF_MATCH'] : false);
// delete
if($httpmethod === 'DELETE' && $cdavdata['etag'] == $etag)
if($httpmethod === 'DELETE' && $cdavdata['etag'] == $etag) {
Libsync::build_sync_packet($channel['channel_id'], [
$sync => [
'action' => 'delete_card',
@@ -206,18 +208,18 @@ class Cdav extends Controller {
'carduri' => $uri
]
]);
}
else {
if($etag) {
if($etag && $cdavdata['etag'] !== $etag) {
// update
if($cdavdata['etag'] !== $etag)
Libsync::build_sync_packet($channel['channel_id'], [
$sync => [
'action' => 'update_card',
'uri' => $cdavdata['uri'],
'carduri' => $uri,
'card' => $httpbody
]
]);
Libsync::build_sync_packet($channel['channel_id'], [
$sync => [
'action' => 'update_card',
'uri' => $cdavdata['uri'],
'carduri' => $uri,
'card' => $httpbody
]
]);
}
else {
// new
@@ -235,7 +237,6 @@ class Cdav extends Controller {
}
}
$principalBackend = new \Sabre\DAVACL\PrincipalBackend\PDO($pdo);
$carddavBackend = new \Sabre\CardDAV\Backend\PDO($pdo);
$caldavBackend = new \Sabre\CalDAV\Backend\PDO($pdo);
@@ -268,7 +269,7 @@ class Cdav extends Controller {
// Plugins
$server->addPlugin(new \Sabre\DAV\Auth\Plugin($auth));
//$server->addPlugin(new \Sabre\DAV\Browser\Plugin());
// $server->addPlugin(new \Sabre\DAV\Browser\Plugin());
$server->addPlugin(new \Sabre\DAV\Sync\Plugin());
$server->addPlugin(new \Sabre\DAV\Sharing\Plugin());
$server->addPlugin(new \Sabre\DAVACL\Plugin());
@@ -276,7 +277,7 @@ class Cdav extends Controller {
// CalDAV plugins
$server->addPlugin(new \Sabre\CalDAV\Plugin());
$server->addPlugin(new \Sabre\CalDAV\SharingPlugin());
//$server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin());
// $server->addPlugin(new \Sabre\CalDAV\Schedule\Plugin());
$server->addPlugin(new \Sabre\CalDAV\ICSExportPlugin());
// CardDAV plugins

View File

@@ -27,7 +27,7 @@ class Channel extends Controller {
function init() {
if (in_array(substr($_GET['search'], 0, 1), ['@', '!', '?']) || strpos($_GET['search'], 'https://') === 0)
if (array_key_exists('search', $_GET) && (in_array(substr($_GET['search'], 0, 1), ['@', '!', '?']) || strpos($_GET['search'], 'https://') === 0))
goaway(z_root() . '/search?f=&search=' . $_GET['search']);
$which = null;
@@ -155,7 +155,7 @@ class Channel extends Controller {
intval($channel['channel_id'])
);
opengraph_add_meta($r ? $r[0] : [], $channel);
opengraph_add_meta((isset($r) && count($r) ? $r[0] : []), $channel);
}
function get($update = 0, $load = false) {
@@ -168,7 +168,7 @@ class Channel extends Controller {
if (strpos($mid, 'b64.') === 0)
$decoded = @base64url_decode(substr($mid, 4));
if ($decoded)
if (isset($decoded))
$mid = $decoded;
$datequery = ((x($_GET, 'dend') && is_a_date_arg($_GET['dend'])) ? notags($_GET['dend']) : '');
@@ -308,9 +308,9 @@ class Channel extends Controller {
if (($update) && (!$load)) {
if ($mid) {
$r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal_update
$r = q("SELECT parent AS item_id from item where mid = '%s' and uid = %d $item_normal_update
AND item_wall = 1 $simple_update $sql_extra limit 1",
dbesc($mid . '%'),
dbesc($mid),
intval(App::$profile['profile_uid'])
);
}
@@ -328,6 +328,7 @@ class Channel extends Controller {
}
else {
$sql_extra2 = '';
if (x($category)) {
$sql_extra2 .= protect_sprintf(term_item_parent_query(App::$profile['profile_uid'], 'item', $category, TERM_CATEGORY));
}
@@ -355,9 +356,9 @@ class Channel extends Controller {
if ($noscript_content || $load) {
if ($mid) {
$r = q("SELECT parent AS item_id from item where mid like '%s' and uid = %d $item_normal
$r = q("SELECT parent AS item_id from item where mid = '%s' and uid = %d $item_normal
AND item_wall = 1 $sql_extra limit 1",
dbesc($mid . '%'),
dbesc($mid),
intval(App::$profile['profile_uid'])
);
if (!$r) {
@@ -419,7 +420,7 @@ class Channel extends Controller {
if ((!$update) && (!$load)) {
if ($decoded)
if (isset($decoded))
$mid = 'b64.' . base64url_encode($mid);
// This is ugly, but we can't pass the profile_uid through the session to the ajax updater,
@@ -485,7 +486,7 @@ class Channel extends Controller {
$o .= conversation($items, $mode, $update, $page_mode);
if ($mid && $items[0]['title'])
if ($mid && count($items) > 0 && isset($items[0]['title']))
App::$page['title'] = $items[0]['title'] . " - " . App::$page['title'];
}

View File

@@ -116,7 +116,7 @@ class Channel_calendar extends Controller {
if ($results) {
// Set permissions based on tag replacements
set_linkified_perms($results, $str_contact_allow, $str_group_allow, $uid, false, $private);
set_linkified_perms($results, $str_contact_allow, $str_group_allow, $uid, $private);
foreach ($results as $result) {
$success = $result['success'];

View File

@@ -123,7 +123,8 @@ class Cloud extends Controller {
notice( t('Permission denied') . EOL);
}
elseif($err instanceof \Sabre\DAV\Exception\NotImplemented) {
notice( t('Please refresh page') . EOL);
// notice( t('Please refresh page') . EOL);
goaway(z_root() . '/' . \App::$query_string);
}
else {
notice( t('Unknown error') . EOL);

View File

@@ -18,11 +18,11 @@ class Connect extends Controller {
App::$error = 404;
return;
}
$r = q("select * from channel where channel_address = '%s' limit 1",
dbesc($which)
);
if($r)
App::$data['channel'] = $r[0];
@@ -30,36 +30,36 @@ class Connect extends Controller {
profile_load($which,'');
}
function post() {
if(! array_key_exists('channel', App::$data))
return;
$channel_id = App::$data['channel']['channel_id'];
$edit = ((local_channel() && (local_channel() == $channel_id)) ? true : false);
if($edit) {
$has_premium = ((App::$data['channel']['channel_pageflags'] & PAGE_PREMIUM) ? 1 : 0);
$premium = (($_POST['premium']) ? intval($_POST['premium']) : 0);
$text = escape_tags($_POST['text']);
if($has_premium != $premium) {
$r = q("update channel set channel_pageflags = ( channel_pageflags %s %d ) where channel_id = %d",
db_getfunc('^'),
intval(PAGE_PREMIUM),
intval(local_channel())
intval(local_channel())
);
\Zotlabs\Daemon\Master::Summon(array('Notifier','refresh_all',$channel_id));
}
set_pconfig($channel_id,'system','selltext',$text);
// reload the page completely to get fresh data
goaway(z_root() . '/' . App::$query_string);
}
$url = '';
$observer = App::get_observer();
if(($observer) && ($_POST['submit'] === t('Continue'))) {
@@ -70,18 +70,18 @@ class Connect extends Controller {
dbesc($observer['xchan_hash'])
);
if($r)
$url = $r[0]['hubloc_url'] . '/follow?f=&url=' . urlencode(channel_reddress(App::$data['channel']));
$url = $r[0]['hubloc_url'] . '/follow?f=&interactive=1&url=' . urlencode(channel_reddress(App::$data['channel']));
}
}
if($url)
goaway($url . '&confirm=1');
else
notice('Unable to connect to your home hub location.');
}
function get() {
if(! array_key_exists('channel', App::$data))
@@ -90,11 +90,11 @@ class Connect extends Controller {
$channel_id = App::$data['channel']['channel_id'];
$edit = ((local_channel() && (local_channel() == $channel_id)) ? true : false);
$text = get_pconfig($channel_id,'system','selltext');
if($edit) {
$o = replace_macros(get_markup_template('sellpage_edit.tpl'),array(
'$header' => t('Premium Channel Setup'),
'$address' => App::$data['channel']['channel_address'],
@@ -105,36 +105,36 @@ class Connect extends Controller {
'$lbl2' => t('Potential connections will then see the following text before proceeding:'),
'$desc2' => t('By continuing, I certify that I have complied with any instructions provided on this page.'),
'$submit' => t('Submit'),
));
return $o;
}
else {
if(! $text)
$text = t('(No specific instructions have been provided by the channel owner.)');
$submit = replace_macros(get_markup_template('sellpage_submit.tpl'), array(
'$continue' => t('Continue'),
'$continue' => t('Continue'),
'$address' => App::$data['channel']['channel_address']
));
$o = replace_macros(get_markup_template('sellpage_view.tpl'),array(
'$header' => t('Restricted or Premium Channel'),
'$desc' => t('This channel may require additional steps or acknowledgement of the following conditions prior to connecting:'),
'$text' => prepare_text($text),
'$text' => prepare_text($text),
'$desc2' => t('By continuing, I certify that I have complied with any instructions provided on this page.'),
'$submit' => $submit,
));
$arr = array('channel' => App::$data['channel'],'observer' => App::get_observer(), 'sellpage' => $o, 'submit' => $submit);
call_hooks('connect_premium', $arr);
$o = $arr['sellpage'];
}
return $o;
}
}

View File

@@ -245,7 +245,7 @@ class Directory extends Controller {
$profile_link = chanlink_url($rr['url']);
$pdesc = (($rr['description']) ? $rr['description'] . '<br />' : '');
$connect_link = ((local_channel()) ? z_root() . '/follow?f=&url=' . urlencode($rr['address']) : '');
$connect_link = ((local_channel()) ? z_root() . '/follow?f=&interactive=1&url=' . urlencode($rr['address']) : '');
// Checking status is disabled ATM until someone checks the performance impact more carefully
//$online = remote_online_status($rr['address']);

View File

@@ -97,8 +97,8 @@ class Display extends \Zotlabs\Web\Controller {
if($decoded)
$item_hash = $decoded;
$r = q("select id, uid, mid, parent, parent_mid, thr_parent, verb, item_type, item_deleted, author_xchan, item_blocked from item where mid like '%s' limit 1",
dbesc($item_hash . '%')
$r = q("select id, uid, mid, parent, parent_mid, thr_parent, verb, item_type, item_deleted, author_xchan, item_blocked from item where mid = '%s' limit 1",
dbesc($item_hash)
);
if($r) {
@@ -247,69 +247,62 @@ class Display extends \Zotlabs\Web\Controller {
if($noscript_content || $load) {
$r = null;
require_once('include/channel.php');
$sys = get_sys_channel();
$sysid = $sys['channel_id'];
// in case somebody turned off public access to sys channel content using permissions
// make that content unsearchable by ensuring the owner uid can't match
$sys_id = perm_is_allowed($sys['channel_id'], $observer_hash, 'view_stream') ? $sys['channel_id'] : 0;
$r = null;
if(local_channel()) {
$r = q("SELECT item.id as item_id from item WHERE uid = %d and mid = '%s' $item_normal limit 1",
$r = q("SELECT item.id AS item_id FROM item WHERE uid = %d AND mid = '%s' $item_normal LIMIT 1",
intval(local_channel()),
dbesc($target_item['parent_mid'])
);
}
if($r === null) {
// in case somebody turned off public access to sys channel content using permissions
// make that content unsearchable by ensuring the owner uid can't match
if(! perm_is_allowed($sysid,$observer_hash,'view_stream'))
$sysid = 0;
$r = q("SELECT item.id as item_id from item
if(!$r) {
$r = q("SELECT item.id AS item_id FROM item
WHERE ((mid = '%s'
AND (((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = ''
AND (((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = ''
AND item.deny_gid = '' AND item_private = 0 )
and uid in ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
AND uid IN ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
OR uid = %d ))) OR
(mid = '%s' $sql_extra ))
$item_normal
limit 1",
dbesc($target_item['parent_mid']),
intval($sysid),
intval($sys_id),
dbesc($target_item['parent_mid'])
);
}
}
elseif($update && !$load) {
$r = null;
require_once('include/channel.php');
$sys = get_sys_channel();
$sysid = $sys['channel_id'];
// in case somebody turned off public access to sys channel content using permissions
// make that content unsearchable by ensuring the owner uid can't match
$sys_id = perm_is_allowed($sys['channel_id'], $observer_hash, 'view_stream') ? $sys['channel_id'] : 0;
$r = null;
if(local_channel()) {
$r = q("SELECT item.parent AS item_id from item
WHERE uid = %d
and parent_mid = '%s'
AND parent_mid = '%s'
$item_normal_update
$simple_update
limit 1",
LIMIT 1",
intval(local_channel()),
dbesc($target_item['parent_mid'])
);
}
if($r === null) {
// in case somebody turned off public access to sys channel content using permissions
// make that content unsearchable by ensuring the owner_xchan can't match
if(! perm_is_allowed($sysid,$observer_hash,'view_stream'))
$sysid = 0;
if(! $r) {
$r = q("SELECT item.id as item_id from item
WHERE ((parent_mid = '%s'
AND (((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = ''
AND (((( item.allow_cid = '' AND item.allow_gid = '' AND item.deny_cid = ''
AND item.deny_gid = '' AND item_private = 0 )
and uid in ( " . stream_perms_api_uids(($observer_hash) ? (PERMS_NETWORK|PERMS_PUBLIC) : PERMS_PUBLIC) . " ))
OR uid = %d ))) OR
@@ -317,14 +310,14 @@ class Display extends \Zotlabs\Web\Controller {
$item_normal
limit 1",
dbesc($target_item['parent_mid']),
intval($sysid),
intval($sys_id),
dbesc($target_item['parent_mid'])
);
}
}
else {
$r = array();
$r = [];
}
if($r) {
@@ -332,7 +325,7 @@ class Display extends \Zotlabs\Web\Controller {
if($parents_str) {
$items = q("SELECT item.*, item.id AS item_id
FROM item
WHERE parent in ( %s ) $item_normal ",
WHERE parent in ( %s ) $sql_extra $item_normal ",
dbesc($parents_str)
);
xchan_query($items);

View File

@@ -14,7 +14,7 @@ use Zotlabs\Daemon\Master;
class Follow extends Controller {
function init() {
if (ActivityStreams::is_as_request() && argc() == 2) {
$abook_id = intval(argv(1));
@@ -73,11 +73,11 @@ class Follow extends Controller {
$url = notags(trim(punify($_REQUEST['url'])));
$return_url = $_SESSION['return_url'];
$confirm = intval($_REQUEST['confirm']);
$interactive = (($_REQUEST['interactive']) ? intval($_REQUEST['interactive']) : 1);
$interactive = (($_REQUEST['interactive']) ? intval($_REQUEST['interactive']) : 1);
$channel = App::get_channel();
$result = Connect::connect($channel,$url);
if ($result['success'] == false) {
if ($result['message']) {
notice($result['message']);
@@ -89,9 +89,9 @@ class Follow extends Controller {
json_return_and_die($result);
}
}
info( t('Connection added.') . EOL);
$clone = array();
foreach ($result['abook'] as $k => $v) {
if (strpos($k,'abook_') === 0) {
@@ -101,30 +101,30 @@ class Follow extends Controller {
unset($clone['abook_id']);
unset($clone['abook_account']);
unset($clone['abook_channel']);
$abconfig = load_abconfig($channel['channel_id'],$clone['abook_xchan']);
if ($abconfig) {
$clone['abconfig'] = $abconfig;
}
Libsync::build_sync_packet(0, [ 'abook' => [ $clone ] ], true);
$can_view_stream = their_perms_contains($channel['channel_id'],$clone['abook_xchan'],'view_stream');
// If we can view their stream, pull in some posts
if (($can_view_stream) || ($result['abook']['xchan_network'] === 'rss')) {
Master::Summon([ 'Onepoll', $result['abook']['abook_id'] ]);
}
if ($interactive) {
goaway(z_root() . '/connedit/' . $result['abook']['abook_id'] . '?follow=1');
}
else {
json_return_and_die([ 'success' => true ]);
}
}
function get() {
if (! local_channel()) {
return login();

View File

@@ -41,7 +41,7 @@ class Hq extends \Zotlabs\Web\Controller {
if(argc() > 1 && argv(1) !== 'load') {
$item_hash = argv(1);
}
if($_REQUEST['mid'])
$item_hash = $_REQUEST['mid'];
@@ -49,9 +49,9 @@ class Hq extends \Zotlabs\Web\Controller {
$item_normal_update = item_normal_update();
if(! $item_hash) {
$r = q("SELECT mid FROM item
$r = q("SELECT mid FROM item
WHERE uid = %d $item_normal
AND mid = parent_mid
AND mid = parent_mid
ORDER BY created DESC LIMIT 1",
intval(local_channel())
);
@@ -71,10 +71,10 @@ class Hq extends \Zotlabs\Web\Controller {
$target_item = null;
$r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where mid like '%s' limit 1",
dbesc($item_hash . '%')
$r = q("select id, uid, mid, parent_mid, thr_parent, verb, item_type, item_deleted, item_blocked from item where mid = '%s' limit 1",
dbesc($item_hash)
);
if($r) {
$target_item = $r[0];
}
@@ -83,7 +83,7 @@ class Hq extends \Zotlabs\Web\Controller {
if($target_item['item_blocked'] == ITEM_MODERATED) {
goaway(z_root() . '/moderate/' . $target_item['id']);
}
$simple_update = '';
if($update && $_SESSION['loadtime'])
$simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
@@ -94,16 +94,16 @@ class Hq extends \Zotlabs\Web\Controller {
$sys_item = false;
}
if(! $update) {
$channel = \App::get_channel();
$channel_acl = [
'allow_cid' => $channel['channel_allow_cid'],
'allow_gid' => $channel['channel_allow_gid'],
'deny_cid' => $channel['channel_deny_cid'],
'allow_cid' => $channel['channel_allow_cid'],
'allow_gid' => $channel['channel_allow_gid'],
'deny_cid' => $channel['channel_deny_cid'],
'deny_gid' => $channel['channel_deny_gid']
];
];
$x = [
'is_owner' => true,
@@ -143,7 +143,7 @@ class Hq extends \Zotlabs\Web\Controller {
// if the target item is not a post (eg a like) we want to address its thread parent
//$mid = ((($target_item['verb'] == ACTIVITY_LIKE) || ($target_item['verb'] == ACTIVITY_DISLIKE)) ? $target_item['thr_parent'] : $target_item['mid']);
$mid = $target_item['mid'];
// if we got a decoded hash we must encode it again before handing to javascript
// if we got a decoded hash we must encode it again before handing to javascript
if($decoded)
$mid = 'b64.' . base64url_encode($mid);
}
@@ -154,7 +154,7 @@ class Hq extends \Zotlabs\Web\Controller {
$o .= '<div id="live-hq"></div>' . "\r\n";
$o .= "<script> var profile_uid = " . local_channel()
. "; var netargs = '?f='; var profile_page = " . \App::$pager['page'] . ";</script>\r\n";
\App::$page['htmlhead'] .= replace_macros(get_markup_template("build_query.tpl"),[
'$baseurl' => z_root(),
'$pgtype' => 'hq',
@@ -241,14 +241,14 @@ class Hq extends \Zotlabs\Web\Controller {
else {
$r = [];
}
if($r) {
$items = q("SELECT item.*, item.id AS item_id
$items = q("SELECT item.*, item.id AS item_id
FROM item
WHERE parent = '%s' $item_normal ",
dbesc($r[0]['item_id'])
);
xchan_query($items,true,(($sys_item) ? local_channel() : 0));
$items = fetch_post_tags($items,true);
$items = conv_sort($items,'created');

View File

@@ -209,12 +209,6 @@ class Import extends \Zotlabs\Web\Controller {
logger('import step 3');
if(is_array($data['hubloc'])) {
import_hublocs($channel,$data['hubloc'],$seize,$moving);
}
logger('import step 4');
// create new hubloc for the new channel at this site
if(array_key_exists('channel',$data)) {
@@ -277,7 +271,7 @@ class Import extends \Zotlabs\Web\Controller {
}
logger('import step 5');
logger('import step 4');
// import xchans and contact photos
@@ -335,7 +329,7 @@ class Import extends \Zotlabs\Web\Controller {
}
logger('import step 6');
logger('import step 5');
// import xchans
$xchans = $data['xchan'];
@@ -404,7 +398,14 @@ class Import extends \Zotlabs\Web\Controller {
}
}
logger('import step 7');
logger('import step 6');
}
logger('import step 7');
// this must happen after xchans got imported!
if(is_array($data['hubloc'])) {
import_hublocs($channel,$data['hubloc'],$seize,$moving);
}
$friends = 0;

View File

@@ -6,7 +6,7 @@ use Zotlabs\Lib\Apps;
use Zotlabs\Web\Controller;
/**
* module: invite.php
* module: invitexv2.php
*
* send email invitations to join social network
*
@@ -15,91 +15,291 @@ use Zotlabs\Web\Controller;
class Invite extends Controller {
/**
* While coding this, I want to introduce a system of qualified messages and notifications.
* Each message consists of a 3 letter prefix, a 4 digit number and a one letter suffix (PREnnnnS).
* The spirit about is not from me, but many decades used by IBM inc. in devel with best success.
*
* The system prefix, used uppercase as system message id, lowercase as css and js prefix (classes, ids etc).
* Usually not used as self::MYP, but placed in the code dominant enough for easy to find.
*
* Concrete here:
* The prefix indicates Z for the Zlabs(core), A for Account stuff, I for Invite.
* The numbers scope will be 00xx within/for templates, 01xx for get, 02xx for post functions.
* Message qualification ends with a uppercase suffix, where
* I=Info(only),
* W=Warning(more then info and less then error),
* E=Error,
* F=Fatal(for unexpected errors).
* Btw, in case of using fail2ban, a scan of messages going to log is very much more with ease,
* esspecially in multi language driven systems where messages vary.
*
* @author Hilmar Runge
* @version 2.0.0
* @since 2020-01-20
*
*/
const MYP = 'ZAI';
const VERSION = '2.0.0';
function post() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
// zai02
if (! local_channel()) {
notice( 'ZAI0201E,' .t('Permission denied.') . EOL);
return;
}
if(! Apps::system_app_installed(local_channel(), 'Invite')) {
if (! Apps::system_app_installed(local_channel(), 'Invite')) {
notice( 'ZAI0202E,' . t('Invite App') . ' (' . t('Not Installed') . ')' . EOL);
return;
}
check_form_security_token_redirectOnErr('/', 'send_invite');
$max_invites = intval(get_config('system','max_invites'));
if(! $max_invites)
$max_invites = 50;
$current_invites = intval(get_pconfig(local_channel(),'system','sent_invites'));
if($current_invites > $max_invites) {
notice( t('Total invitation limit exceeded.') . EOL);
$ok = $ko = 0;
$feedbk = '';
$isajax = is_ajax();
$eol = $isajax ? "\n" : EOL;
$policy = intval(get_config('system','register_policy'));
if ($policy == REGISTER_CLOSED) {
notice( 'ZAI0212E,' . t('Register is closed') . ')' . EOL);
return;
};
$recips = ((x($_POST,'recipients')) ? explode("\n",$_POST['recipients']) : array());
$message = ((x($_POST,'message')) ? notags(trim($_POST['message'])) : '');
$total = 0;
if(get_config('system','invitation_only')) {
$invonly = true;
$x = get_pconfig(local_channel(),'system','invites_remaining');
if((! $x) && (! is_site_admin()))
return;
}
foreach($recips as $recip) {
$recip = trim($recip);
if(! $recip)
continue;
if(! validate_email($recip)) {
notice( sprintf( t('%s : Not a valid email address.'), $recip) . EOL);
continue;
}
else
$nmessage = $message;
$account = App::get_account();
$res = z_mail(
[
'toEmail' => $recip,
'fromName' => ' ',
'fromEmail' => $account['account_email'],
'messageSubject' => t('Please join us on $Projectname'),
'textVersion' => $nmessage,
]
);
if($res) {
$total ++;
$current_invites ++;
set_pconfig(local_channel(),'system','sent_invites',$current_invites);
if($current_invites > $max_invites) {
notice( t('Invitation limit exceeded. Please contact your site administrator.') . EOL);
return;
if ($policy == REGISTER_OPEN)
$flags = 0;
elseif ($policy == REGISTER_APPROVE)
$flags = ACCOUNT_PENDING;
$flags = ($flags | intval(get_config('system','verify_email')));
// how many max recipients in one mail submit
$maxto = get_config('system','invitation_max_recipients', 'na');
If (is_site_admin()) {
// set, if admin is operator, default to 12
if ($maxto === 'na') set_config('system','invitation_max_recipients', 12);
}
$maxto = ($maxto === 'na') ? 12 : $maxto;
// language code current for the invitation
$lcc = x($_POST['zailcc']) && preg_match('/[a-z\-]{2,5}/', $_POST['zailcc'])
? $_POST['zailcc']
: '';
// expiration duration amount quantity, in case of doubts defaults 2
$durn = x($_POST['zaiexpiren']) && preg_match('/[0-9]{1,2}/', $_POST['zaiexpiren'])
? trim(intval($_POST['zaiexpiren']))
: '2';
!$durn ? $durn = 2 : '';
// expiration duration unit 1st letter (day, weeks, months, years), defaults days
$durq = x($_POST['zaiexpire']) && preg_match('/[ihd]{1,1}/', $_POST['zaiexpire'])
? $_POST['zaiexpire']
: 'd';
$dur = self::calcdue($durn.$durq);
$due = t('Note, the invitation code is valid up to') . ' ' . $dur['due'];
if ($isajax) {
$feedbk .= 'ZAI0207I ' . $due . $eol;
}
// take the received email addresses and discart duplicates
$recips = array_filter( array_unique( preg_replace('/^\s*$/', '',
((x($_POST,'zaito')) ? explode( "\n",$_POST['zaito']) : array() ) )));
$havto = count($recips);
if ( $havto > $maxto) {
$feedbk .= 'ZAI0210E ' . sprintf( t('Too many recipients for one invitation (max %d)'), $maxto) . $eol;
$ko++;
} elseif ( $havto == 0 ) {
$feedbk .= 'ZAI0211E ' . t('No recipients for this invitation') . $eol;
$ko++;
} else {
// each email address
foreach($recips as $n => $recip) {
// if empty ignore
$recip = $recips[$n] = trim($recip);
if(! $recip) continue;
// see if we have an email address who@domain.tld
if (!preg_match('/^.{2,64}\@[a-z0-9.-]{4,32}\.[a-z]{2,12}$/', $recip)) {
$feedbk .= 'ZAI0203E ' . ($n+1) . ': ' . sprintf( t('(%s) : Not a valid email address'), $recip) . $eol;
$ko++;
continue;
}
if(! validate_email($recip)) {
$feedbk .= 'ZAI0204E ' . ($n+1) . ': ' . sprintf( t('(%s) : Not a real email address'), $recip) . $eol;
$ko++;
continue;
}
// do we accept the email (not black listed)
if(! allowed_email($recip)) {
$feedbk .= 'ZAI0205E ' . ($n+1) . ': ' . sprintf( t('(%s) : Not allowed email address'), $recip) . $eol;
$ko++;
continue;
}
// is the email address just in use for account or registered before
$r = q("SELECT account_email AS em FROM account WHERE account_email = '%s'"
. " UNION "
."SELECT reg_email AS em FROM register WHERE reg_vital = 1 AND reg_email = '%s' LIMIT 1;",
dbesc($recip),
dbesc($recip)
);
if($r && $r[0]['em'] == $recip) {
$feedbk .= 'ZAI0206E ' . ($n+1) . ': ' . sprintf( t('(%s) : email address already in use'), $recip) . $eol;
$ko++;
continue;
}
if ($isajax) {
// seems we have an email address acceptable
$feedbk .= 'ZAI0209I ' . ($n+1) . ': ' . sprintf( t('(%s) : Accepted email address'), $recip) . $eol;
}
}
else {
notice( sprintf( t('%s : Message delivery failed.'), $recip) . EOL);
}
}
notice( sprintf( tt("%d message sent.", "%d messages sent.", $total) , $total) . EOL);
if ($isajax) {
// we are not silent on the ajax road
echo json_encode(array('feedbk' => $feedbk, 'due' => $due));
// that mission is complete
killme();
exit;
}
// Total ?todo notice( t('Invitation limit exceeded. Please contact your site administrator.') . EOL);
// any errors up to now in fg?
// down from here, only on the main road (no more ajax)
// tell if sth is to tell
$feedbk ? notice($feedbk) . $eol : '';
if ($ko > 0) return;
// the personal mailtext
$mailtext = ((x($_POST,'zaitxt')) ? notags(trim($_POST['zaitxt'])) : '');
// to log in db
$reonar = json_decode( ((x($_POST,'zaireon')) ? notags(trim($_POST['zaireon'])) : ''), TRUE, 8) ;
// me, the invitor
$account = App::get_account();
$reonar['from'] = $account['account_email'];
$reonar['date'] = datetime_convert();
$reonar['fromip'] = $_SERVER['REMOTE_ADDR'];
// who is the invitor on
$inby = local_channel();
$ok = $ko = 0;
// send the mail(s)
foreach($recips as $n => $recip) {
$reonar['due'] = $due;
$reonar['to'] = $recip;
$reonar['txtpersonal'] = $mailtext;
// generate an invide code to store and pm
$invite_code = autoname(8) . rand(1000,9999);
// again the final localized templates $reonar['subject'] $reonar['lang'] $reonar['tpl']
// save current operators lc and take the desired to mail
push_lang($reonar['lang']);
// resolve
$tx = replace_macros(get_intltext_template('invite.'.$reonar['tpl'].'.tpl'),
array(
'$projectname' => t('$Projectname'),
'$invite_code' => $invite_code,
'$invite_where' => z_root() . '/register',
'$invite_whereami' => str_replace('@', '@+', $reonar['whereami']),
'$invite_whoami' => z_root() . '/channel/' . $reonar['whoami'],
'$invite_anywhere' => z_root() . '/pubsites'
)
);
// restore lc to operator
pop_lang();
$reonar['txttemplate'] = $tx;
// pm
$zem = z_mail(
[
'toEmail' => $recip,
'fromName' => ' ',
'fromEmail' => $reonar['from'],
'messageSubject' => $reonar['subject'],
'textVersion' => ($mailtext ? $mailtext . "\n\n" : '') . $tx . "\n" . $due,
]
);
if(!$zem) {
$ko++;
$msg = 'ZAI0208E,' . sprintf( t('%s : Message delivery failed.'), $recip);
} else {
$ok++;
$msg = 'ZAI0208I ' . sprintf( t('To %s : Message delivery success.'), $recip);
// if verify_email is the rule, email becomes a dId2 - NO
// $did2 = ($flags & ACCOUNT_UNVERIFIED) == ACCOUNT_UNVERIFIED ? $recip : '';
// always enforce verify email with invitations, thus email becomes a dId2
$did2 = $recip;
$flags |= ACCOUNT_UNVERIFIED;
// defaults vital, reg_pass
$r = q("INSERT INTO register ("
. "reg_flags,reg_didx,reg_did2,reg_hash,reg_created,reg_startup,reg_expires,reg_email,reg_byc,reg_uid,reg_atip,reg_lang,reg_stuff)"
. " VALUES ( %d, 'i', '%s', '%s', '%s', '%s', '%s', '%s', %d, %d, '%s', '%s', '%s') ",
intval($flags),
dbesc($did2),
dbesc($invite_code),
dbesc(datetime_convert()),
dbesc(datetime_convert()),
dbesc($dur['due']),
dbesc($recip),
intval($inby),
intval($account['account_id']),
dbesc($reonar['fromip']),
dbesc($reonar['lang']),
dbesc(json_encode( array('reon' => $reonar) ))
);
}
$msg .= ' (a' . $account['account_id'] . ', c' . $inby . ', from:' . $reonar['from'] . ')';
zar_log( $msg);
}
$ok + $ko > 0
? notice( 'ZAI0212I ' . sprintf( t('%1$d mail(s) sent, %2$d mail error(s)'), $ok, $ko) . EOL)
: '';
//logger( print_r( $reonar, true) );
return;
}
function get() {
// zai1
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
notice( 'ZAI0101E,' . t('Permission denied.') . EOL);
return;
}
@@ -107,68 +307,267 @@ class Invite extends Controller {
//Do not display any associated widgets at this point
App::$pdl = '';
$o = '<b>' . t('Invite App') . ' (' . t('Not Installed') . '):</b><br>';
$o .= t('Send email invitations to join this network');
$o = 'ZAI0102E,' . t('Invite App') . ' (' . t('Not Installed') . ')' . EOL;
return $o;
}
nav_set_selected('Invite');
$tpl = get_markup_template('invite.tpl');
$invonly = false;
if(get_config('system','invitation_only')) {
$invonly = true;
$x = get_pconfig(local_channel(),'system','invites_remaining');
if((! $x) && (! is_site_admin())) {
notice( t('You have no more invitations available') . EOL);
if (! (get_config('system','invitation_also') || get_config('system','invitation_only')) ) {
$o = 'ZAI0103E,' . t('Invites not proposed by configuration') . '. ';
$o .= t('Contact the site admin');
return $o;
}
// invitation_by_user may still not configured, the default 'na' will tell this
// if configured, 0 disables invitations by users, other numbers are how many invites a user may propagate
$invuser = get_config('system','invitation_by_user', 'na');
// if the mortal user drives the invitation
If (! is_site_admin()) {
// when not configured, 4 is the default
$invuser = ($invuser === 'na') ? 4 : $invuser;
// a config value 0 disables invitation by users
if (!$invuser) {
$o = 'ZAI0104E, ' . t('Invites by users not enabled') . '. ';
return $o;
}
if ($ihave >= $invuser) {
notice( 'ZAI0105W,' . t('You have no more invitations available') . EOL);
return '';
}
} else {
// general deity admin invite limit infinite (theoretical)
if ($invuser === 'na') set_config('system','invitation_by_user', 4);
// for display only
$invuser = '∞';
}
if($invonly && ($x || is_site_admin())) {
$invite_code = autoname(8) . rand(1000,9999);
$nmessage = str_replace('$invite_code',$invite_code,$message);
$r = q("INSERT INTO register (hash,created,uid,password,lang) VALUES ('%s', '%s',0,'','') ",
dbesc($invite_code),
dbesc(datetime_convert())
);
if(! is_site_admin()) {
$x --;
if($x >= 0)
set_pconfig(local_channel(),'system','invites_remaining',$x);
else
return;
}
}
// xchan record of the page observer
// while quoting matters the user, the sending is associated with a channel (of the user)
// also the admin may and should decide, which channel will told to the public
$ob = App::get_observer();
if(! $ob)
return $o;
$channel = App::get_channel();
return 'ZAI0109F,' . t('Not on xchan') . EOL;
$whereami = $ob['xchan_addr'];
$channel = App::get_channel();
$whoami = $channel['channel_address'];
// to pass also to post()
$tao = 'tao.zai.whereami = ' . "'" . $whereami . "';\n"
. 'tao.zai.whoami = ' . "'" . $whoami . "';\n";
// expirations, duration interval
$dur = self::calcdue();
$tao .= 'tao.zai.expire = { durn: ' . $dur['durn']
. ', durq: ' . "'" . $dur['durq'] . "'"
. ', due: ' . "'" . $dur['due'] . "' };\n";
// to easy redisplay the empty form
nav_set_selected('Invite');
// inform about the count of invitations we have at all
$r = q("SELECT count(reg_id) as ct FROM register WHERE reg_vital = 1"); // where not admin TODO
$wehave = ($r ? $r[0]['ct'] : 0);
// invites max for all users except admins
$invmaxau = intval(get_config('system','invitations_max_users'));
if(! $invmaxau) {
$invmaxau = 50;
if (is_site_admin()) {
set_config('system','invitations_max_users',intval($invmaxau));
}
}
if ($wehave > $invmaxau) {
if (! is_site_admin()) {
$feedbk .= 'ZAI0200E,' . t('All users invitation limit exceeded.') . $eol;
}
}
// let see how many invites currently used by the user
$r = q("SELECT count(reg_id) AS n FROM register WHERE reg_vital = 1 AND reg_byc = %d",
intval(local_channel()));
$ihave = $r ? $r[0]['n'] : 0;
$tpl = get_markup_template('invite.tpl');
$inv_rabots = array(
'i' => t('Minute(s)'),
'h' => t('Hour(s)') ,
'd' => t('Day(s)')
);
$inv_expire = replace_macros(get_markup_template('field_duration.qmc.tpl'),
array(
'label' => t('Invitation expires after'),
'qmc' => 'zai',
'qmcid' => 'ZAI0014I',
'field' => array(
'name' => 'expire',
'title' => t('duration up from now'),
'value' => ($invexpire_n ? $invexpire_n : 2),
'min' => '1',
'max' => '99',
'size' => '2',
'default' => ($invexpire_u ? $invexpire_u : 'd')
),
'rabot' => $inv_rabots
)
);
// let generate an invite code that here and never will be applied (only to fill displayed template)
// real invite codes become generated for each recipient when we store the new invitation(s)
// $invite_code = substr(str_shuffle('abcdefghijklmnopqrstuvwxyz'), 0, 8) . rand(1000,9999);
// let take one descriptive for template (as said is never used)
$invite_code = 'INVITATE2020';
// what languages we use now
$lccmy = ((isset(App::$config['system']['language'])) ? App::$config['system']['language'] : 'en');
// and all the localized templates belonging to invite
$tpls = glob('view/*/invite.*.tpl');
$tpla=$tplx=$tplxs=array();
foreach ($tpls as $tpli) {
list( $nop, $l, $t ) = explode( '/', $tpli);
if ( preg_match('/\.subject/', $t) =='1' ) {
// indicate a subject tpl exists
$t=str_replace(array('invite.', '.subject', '.tpl'), '', $t);
$tplxs[$l][$t]=true;
continue;
}
// collect unique template names cross all languages and
// tpla[language][]=template those available in each language
$tplx[] = $tpla[$l][] = str_replace( array('invite.', '.tpl'), '', $t);
}
$langs = array_keys($tpla);
asort($langs);
$tplx = array_unique($tplx);
asort($tplx);
// prepare current language and the default standard template (causual) for js
// With and in js, I use a var 'tao' as a shortcut for top array object
// and also qualify the object with the prefix zai = tao.zai as my var used outsite functions
// can be unique within the overall included spaghette whirls
// one can say Im too lazy to write prototypes and just I can agree.
// tao simply applies the fact of using the same var as object and/or array in ja.
$tao.='tao.zai.lccmy = ' . "'" . $lccmy . "';\n" . 'tao.zai.itpl = ' . "'" . 'casual' . "';\n";
$lcclane=$tx=$tplin='';
//$lccsym='<span class="fa zai_fa zai_lccsym"></span>'; // alt 
$tplsym='<span class="fa zai_fa"></span>';
// I will uncomment for js console debug
// $tao.='tao.zai.debug = ' . "'" . json_encode($tplxs) . "';\n";
// running thru the localized templates (subjects and textmsgs) and bring them to tao
// lcc LanguageCountryCode,
// lcc2 is a 2 character and lcc5 a 5 character LanguageCountryCode
foreach($tpla as $l => $tn) {
// restyle lc to iso getttext format to avoid errors in js, hilite the current
$lcc = str_replace('-', '_', $l);
$hi = ($l == $lccmy) ? ' zai_hi' : '';
$lcc2 = strlen($l) == 2 ? ' zai_lcc2' : '';
$lcc5 = strlen($l) == 5 ? ' zai_lcc5' : '';
$lccg = ' zai_lccg' . substr( $l, 0, 2 );
$lcclane
.= '<span class="fa zai_fa zai_lccsym' . $lcc2 . $lcc5 . $lccg . '"></span>'
. '<a href="javascript:;" class="zai_lcc' . $lcc2 . $lcc5 . $lccg . $hi . '">' . $lcc . '</a>';
// textmsg
$tao .= 'tao.zai.t.' . $lcc . ' = {};' . "\n";
// subject
$tao .= 'tao.zai.s.' . $lcc . ' = {};' . "\n";
// resolve localized templates and take intented lc for
foreach($tn as $t1) {
// save current lc and take the desired
push_lang($l);
// resolve
$tx = replace_macros(get_intltext_template('invite.'.$t1.'.tpl'),
array(
'$projectname' => t('$Projectname'),
'$invite_code' => $invite_code,
'$invite_where' => z_root() . '/register',
'$invite_whereami' => $whereami,
'$invite_whoami' => z_root() . '/channel/' . $whoami,
'$invite_anywhere' => z_root() . '/pubsites'
)
);
// a default subject if no associated exists
$ts=t('Invitation');
if ( $tplxs[$l][$t1] )
$ts = replace_macros(get_intltext_template('invite.'.$t1.'.subject.tpl'),
array(
'$projectname' => t('$Projectname'),
'$invite_loc' => get_config('system','sitename')
)
);
// restore lc to current foreground
pop_lang();
// bring to tao as js like it
$tao .= 'tao.zai.t.' . $lcc . '.' . $t1 . " = '" . rawurlencode($tx) . "';\n";
$tao .= 'tao.zai.s.' . $lcc . '.' . $t1 . " = '" . rawurlencode($ts) . "';\n";
}
}
// hilite the current defauls just from the beginning
foreach ($tplx as $t1) {
$hi = ($t1 == 'casual') ? ' zai_hi' : '';
$tplin .= $tplsym.'<a href="javascript:;" id="zai-' . $t1
. '" class="invites'.$hi.'">' . $t1 . '</a>';
}
// fill the form for foreground
$o = replace_macros($tpl, array(
'$form_security_token' => get_form_security_token("send_invite"),
'$zai' => strtolower(self::MYP),
'$tao' => $tao,
'$invite' => t('Send invitations'),
'$addr_text' => t('Enter email addresses, one per line:'),
'$msg_text' => t('Your message:'),
'$default_message' => t('Please join my community on $Projectname.') . "\r\n" . "\r\n"
. $linktxt
. (($invonly) ? "\r\n" . "\r\n" . t('You will need to supply this invitation code:') . " " . $invite_code . "\r\n" . "\r\n" : '')
. t('1. Register at any $Projectname location (they are all inter-connected)')
. "\r\n" . "\r\n" . z_root() . '/register'
. "\r\n" . "\r\n" . t('2. Enter my $Projectname network address into the site searchbar.')
. "\r\n" . "\r\n" . $ob['xchan_addr'] . ' (' . t('or visit') . " " . z_root() . '/channel/' . $channel['channel_address'] . ')'
. "\r\n" . "\r\n"
. t('3. Click [Connect]')
. "\r\n" . "\r\n" ,
'$ihave' => 'ZAI0106I, ' . t('Invitations I am using') . ': ' . $ihave . ' / ' . $invuser,
'$wehave' => 'ZAI0107I, ' . t('Invitations we are using') . ': ' . $wehave . ' / ' . $invmaxau,
'$n10' => 'ZAI0010I', '$m10' => t('§ Note, the email(s) sent will be recorded in the system logs'),
'$n11' => 'ZAI0011I', '$m11' => t('Enter email addresses, one per line:'),
'$n12' => 'ZAI0012I', '$m12' => t('Your message:'),
'$n13' => 'ZAI0013I', '$m13' => t('Invite template'),
'$inv_expire' => $inv_expire,
'$subject_label' => t('Subject:'),
'$subject' => t('Invitation'),
'$lcclane' => $lcclane,
'$tplin' => $tplin,
'$standard_message' => '',
'$personal_message' => '',
'$personal_pointer' => t('Here you may enter personal notes to the recipient(s)'),
'$due' => t('Note, the invitation code is valid up to') . ' ' . $dur['due'],
'$submit' => t('Submit')
));
return $o;
}
function calcdue($duri=false) {
// expirations, duration interval
if ($duri===false)
$duri = get_config('system','register_expire', '2d');
if ( preg_match( '/^[0-9]{1,2}[ihdwmy]{1}$/', $duri ) ) {
$durq = substr($duri, -1);
$durn = substr($duri, 0, -1);
$due = date('Y-m-d H:i:s', strtotime('+' . $durn . ' '
. str_replace( array(':i',':h',':d',':w',':m',':y'),
array('minutes', 'hours', 'days', 'weeks', 'months', 'years'),
(':'.$durq))
));
return array( 'durn' => $durn, 'durq' => $durq, 'due' => $due);
}
return false;
}
}

View File

@@ -840,7 +840,7 @@ class Item extends Controller {
if($results) {
// Set permissions based on tag replacements
set_linkified_perms($results, $str_contact_allow, $str_group_allow, $profile_uid, $parent_item, $private);
set_linkified_perms($results, $str_contact_allow, $str_group_allow, $profile_uid, $private, $parent_item);
foreach($results as $result) {
$success = $result['success'];

View File

@@ -20,8 +20,10 @@ class Network extends \Zotlabs\Web\Controller {
return;
}
if(in_array(substr($_GET['search'],0,1),[ '@', '!', '?']) || strpos($_GET['search'], 'https://') === 0)
goaway(z_root() . '/search?f=&search=' . $_GET['search']);
$search = $_GET['search'] ?? '';
if(in_array(substr($search, 0, 1),[ '@', '!', '?']) || strpos($search, 'https://') === 0)
goaway(z_root() . '/search?f=&search=' . $search);
if(count($_GET) < 2) {
$network_options = get_pconfig(local_channel(),'system','network_page_default');
@@ -80,7 +82,7 @@ class Network extends \Zotlabs\Web\Controller {
break;
}
$search = (($_GET['search']) ? $_GET['search'] : '');
$search = $_GET['search'] ?? '';
if($search) {
if(strpos($search,'#') === 0) {
$hashtags = substr($search,1);
@@ -128,17 +130,19 @@ class Network extends \Zotlabs\Web\Controller {
$pf = ((x($_GET,'pf')) ? $_GET['pf'] : '');
$unseen = ((x($_GET,'unseen')) ? $_GET['unseen'] : '');
if (Apps::system_app_installed(local_channel(),'Affinity Tool')) {
if (Apps::system_app_installed(local_channel(),'Affinity Tool')) {
$affinity_locked = intval(get_pconfig(local_channel(),'affinity','lock',1));
if ($affinity_locked) {
set_pconfig(local_channel(),'affinity','cmin',$cmin);
set_pconfig(local_channel(),'affinity','cmax',$cmax);
set_pconfig(local_channel(),'affinity','cmin',$cmin);
set_pconfig(local_channel(),'affinity','cmax',$cmax);
}
}
}
if(x($_GET,'search') || $file || (!$pf && $cid) || $hashtags || $verb || $category || $conv || $unseen)
$nouveau = true;
$cid_r = [];
if($cid) {
$cid_r = q("SELECT abook.abook_xchan, xchan.xchan_addr, xchan.xchan_name, xchan.xchan_url, xchan.xchan_photo_s, xchan.xchan_pubforum from abook left join xchan on abook_xchan = xchan_hash where abook_id = %d and abook_channel = %d and abook_blocked = 0 limit 1",
intval($cid),
@@ -453,6 +457,8 @@ class Network extends \Zotlabs\Web\Controller {
if($update && $_SESSION['loadtime'])
$simple_update = " AND (( item_unseen = 1 AND item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) OR item.changed > '" . datetime_convert('UTC','UTC',$_SESSION['loadtime']) . "' ) ";
$items = [];
if($nouveau && $load) {
// "New Item View" - show all items unthreaded in reverse created date order
$items = q("SELECT item.*, item.id AS item_id, created FROM item

View File

@@ -11,7 +11,7 @@ class New_channel extends \Zotlabs\Web\Controller {
function init() {
$cmd = ((argc() > 1) ? argv(1) : '');
if($cmd === 'autofill.json') {
require_once('library/urlify/URLify.php');
$result = array('error' => false, 'message' => '');
@@ -20,14 +20,14 @@ class New_channel extends \Zotlabs\Web\Controller {
$x = false;
if(get_config('system','unicode_usernames')) {
$x = punify(mb_strtolower($n));
$x = punify(mb_strtolower($n));
}
if((! $x) || strlen($x) > 64)
$x = strtolower(\URLify::transliterate($n));
$test = array();
// first name
if(strpos($x,' '))
$test[] = legal_webbie(substr($x,0,strpos($x,' ')));
@@ -44,19 +44,19 @@ class New_channel extends \Zotlabs\Web\Controller {
json_return_and_die(check_webbie($test));
}
if($cmd === 'checkaddr.json') {
require_once('library/urlify/URLify.php');
$result = array('error' => false, 'message' => '');
$n = trim($_REQUEST['nick']);
if(! $n) {
$n = trim($_REQUEST['name']);
$n = trim($_REQUEST['name']);
}
$x = false;
if(get_config('system','unicode_usernames')) {
$x = punify(mb_strtolower($n));
$x = punify(mb_strtolower($n));
}
if((! $x) || strlen($x) > 64)
@@ -64,7 +64,7 @@ class New_channel extends \Zotlabs\Web\Controller {
$test = array();
// first name
if(strpos($x,' '))
$test[] = legal_webbie(substr($x,0,strpos($x,' ')));
@@ -80,57 +80,57 @@ class New_channel extends \Zotlabs\Web\Controller {
$test[] = $n;
$test[] = $n . mt_rand(1000,9999);
}
for($y = 0; $y < 100; $y ++)
$test[] = 'id' . mt_rand(1000,9999);
json_return_and_die(check_webbie($test));
}
}
function post() {
$arr = $_POST;
$acc = \App::get_account();
$arr['account_id'] = get_account_id();
// prevent execution by delegated channels as well as those not logged in.
// prevent execution by delegated channels as well as those not logged in.
// get_account_id() returns the account_id from the session. But \App::$account
// may point to the original authenticated account.
// may point to the original authenticated account.
if((! $acc) || ($acc['account_id'] != $arr['account_id'])) {
notice( t('Permission denied.') . EOL );
return;
}
$result = create_identity($arr);
if(! $result['success']) {
notice($result['message']);
return;
}
$newuid = $result['channel']['channel_id'];
change_channel($result['channel']['channel_id']);
$next_page = get_config('system', 'workflow_channel_next', 'profiles');
$next_page = get_config('system', 'workflow_channel_next', 'profiles');
goaway(z_root() . '/' . $next_page);
}
function get() {
$acc = \App::get_account();
if((! $acc) || $acc['account_id'] != get_account_id()) {
notice( t('Permission denied.') . EOL);
return;
}
$default_role = '';
$aid = get_account_id();
if($aid) {
@@ -140,7 +140,7 @@ class New_channel extends \Zotlabs\Web\Controller {
if($r && (! intval($r[0]['total']))) {
$default_role = get_config('system','default_permissions_role','social');
}
$limit = account_service_class_fetch(get_account_id(),'total_identities');
$canadd = true;
if($r && ($limit !== false)) {
@@ -155,7 +155,7 @@ class New_channel extends \Zotlabs\Web\Controller {
}
$name_help = '<span id="name_help_loading" style="display:none">' . t('Loading') . '</span><span id="name_help_text">';
$name_help .= (($default_role)
$name_help .= (($default_role)
? t('Your real name is recommended.')
: t('Examples: "Bob Jameson", "Lisa and her Horses", "Soccer", "Aviation Group"')
);
@@ -176,10 +176,10 @@ class New_channel extends \Zotlabs\Web\Controller {
$nickhub = '@' . \App::get_hostname();
$nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), $nick_help, "*");
$role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel permission role compatible with your usage needs and privacy requirements.') . '<br>' . '<a href="help/member/member_guide#Channel_Permission_Roles" target="_blank">' . t('Read more about channel permission roles') . '</a>',$perm_roles);
$o = replace_macros(get_markup_template('new_channel.tpl'), array(
'$title' => t('Create a Channel'),
'$desc' => t('A channel is a unique network identity. It can represent a person (social network profile), a forum (group), a business or celebrity page, a newsfeed, and many other things.') ,
'$desc' => t('A channel is a unique network identity. It can represent a person (social network profile), a forum (group), a business or celebrity page, a newsfeed, and many other things.') ,
'$label_import' => t('or <a href="import">import an existing channel</a> from another location.'),
'$name' => $name,
'$role' => $role,
@@ -190,10 +190,10 @@ class New_channel extends \Zotlabs\Web\Controller {
'$channel_usage_message' => $channel_usage_message,
'$canadd' => $canadd
));
return $o;
}
}

View File

@@ -6,15 +6,17 @@ require_once('include/bbcode.php');
class Notifications extends \Zotlabs\Web\Controller {
function get() {
if(! local_channel()) {
notice( t('Permission denied.') . EOL);
return;
}
nav_set_selected('Notifications');
$o = '';
$notif_content = '';
$notifications_available = false;
$r = q("select count(*) as total from notify where uid = %d and seen = 0",
intval(local_channel())
@@ -24,7 +26,8 @@ class Notifications extends \Zotlabs\Web\Controller {
and seen = 0 order by created desc limit 50",
intval(local_channel())
);
} else {
}
else {
$r1 = q("select * from notify where uid = %d
and seen = 0 order by created desc limit 50",
intval(local_channel())
@@ -36,12 +39,12 @@ class Notifications extends \Zotlabs\Web\Controller {
);
$r = array_merge($r1,$r2);
}
if($r) {
$notifications_available = 1;
$notifications_available = true;
foreach ($r as $rr) {
$x = strip_tags(bbcode($rr['msg']));
$notif_content = replace_macros(get_markup_template('notify.tpl'),array(
$notif_content .= replace_macros(get_markup_template('notify.tpl'),array(
'$item_link' => z_root().'/notify/view/'. $rr['id'],
'$item_image' => $rr['photo'],
'$item_text' => $x,
@@ -54,15 +57,15 @@ class Notifications extends \Zotlabs\Web\Controller {
else {
$notif_content = t('No more system notifications.');
}
$o .= replace_macros(get_markup_template('notifications.tpl'),array(
'$notif_header' => t('System Notifications'),
'$notif_link_mark_seen' => t('Mark all seen'),
'$notif_content' => $notif_content,
'$notifications_available' => $notifications_available,
));
return $o;
}
}

View File

@@ -11,24 +11,24 @@ require_once('include/security.php');
class Oep extends \Zotlabs\Web\Controller {
function init() {
logger('oep: ' . print_r($_REQUEST,true), LOGGER_DEBUG, LOG_INFO);
$html = ((argc() > 1 && argv(1) === 'html') ? true : false);
if($_REQUEST['url']) {
$_REQUEST['url'] = strip_zids($_REQUEST['url']);
$url = $_REQUEST['url'];
}
if(! $url)
http_status_exit(404, 'Not found');
$maxwidth = $_REQUEST['maxwidth'];
$maxheight = $_REQUEST['maxheight'];
$format = $_REQUEST['format'];
if($format && $format !== 'json')
http_status_exit(501, 'Not implemented');
if(fnmatch('*/photos/*/album/*',$url))
$arr = $this->oep_album_reply($_REQUEST);
elseif(fnmatch('*/photos/*/image/*',$url))
@@ -47,7 +47,7 @@ class Oep extends \Zotlabs\Web\Controller {
$arr = $this->oep_cards_reply($_REQUEST);
elseif(fnmatch('*/articles/*',$url))
$arr = $this->oep_articles_reply($_REQUEST);
if($arr) {
if($html) {
if($arr['type'] === 'rich') {
@@ -61,13 +61,13 @@ class Oep extends \Zotlabs\Web\Controller {
}
killme();
}
http_status_exit(404,'Not found');
}
function oep_display_reply($args) {
$ret = array();
$url = $args['url'];
$maxwidth = intval($args['maxwidth']);
@@ -83,8 +83,8 @@ class Oep extends \Zotlabs\Web\Controller {
$item_normal = item_normal();
$p = q("select * from item where mid like '%s' limit 1",
dbesc($res . '%')
$p = q("select * from item where mid = '%s' limit 1",
dbesc($res)
);
if(! $p)
@@ -92,7 +92,7 @@ class Oep extends \Zotlabs\Web\Controller {
$c = channelx_by_n($p[0]['uid']);
if(! ($c && $res))
return;
@@ -100,27 +100,27 @@ class Oep extends \Zotlabs\Web\Controller {
return;
$sql_extra = item_permissions_sql($c['channel_id']);
$p = q("select * from item where mid like '%s' and uid = %d $sql_extra $item_normal limit 1",
dbesc($res . '%'),
$p = q("select * from item where mid = '%s' and uid = %d $sql_extra $item_normal limit 1",
dbesc($res),
intval($c['channel_id'])
);
if(! $p)
return;
xchan_query($p,true);
$p = fetch_post_tags($p,true);
// This function can get tripped up if the item is already a reshare
// (the multiple share declarations do not parse cleanly if nested)
// (the multiple share declarations do not parse cleanly if nested)
// So build a template with a known nonsense string as the content, and then
// replace that known string with the actual rendered content, sending
// each content layer through bbcode() separately.
$x = '2eGriplW^*Jmf4';
$o = "[share author='".urlencode($p[0]['author']['xchan_name']).
"' profile='".$p[0]['author']['xchan_url'] .
"' avatar='".$p[0]['author']['xchan_photo_s'].
@@ -131,29 +131,29 @@ class Oep extends \Zotlabs\Web\Controller {
if($p[0]['title'])
$o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
$o .= $x;
$o .= $x;
$o .= "[/share]";
$o = bbcode($o);
$o = str_replace($x,bbcode($p[0]['body']),$o);
$ret['type'] = 'rich';
$w = (($maxwidth) ? $maxwidth : 640);
$h = (($maxheight) ? $maxheight : intval($w * 2 / 3));
$ret['html'] = '<div style="width: ' . $w . '; height: ' . $h . '; font-family: sans-serif,arial,freesans;" >' . $o . '</div>';
$ret['width'] = $w;
$ret['height'] = $h;
return $ret;
}
function oep_cards_reply($args) {
$ret = [];
$url = $args['url'];
$maxwidth = intval($args['maxwidth']);
@@ -164,7 +164,7 @@ class Oep extends \Zotlabs\Web\Controller {
$res = $matches[3];
}
if(! ($nick && $res))
return $ret;
return $ret;
$channel = channelx_by_nick($nick);
@@ -187,8 +187,8 @@ class Oep extends \Zotlabs\Web\Controller {
return $ret;
}
$r = q("select * from item
where item.uid = %d and item_type = %d
$r = q("select * from item
where item.uid = %d and item_type = %d
$sql_extra order by item.created desc",
intval($channel['channel_id']),
intval(ITEM_TYPE_CARD)
@@ -208,7 +208,7 @@ class Oep extends \Zotlabs\Web\Controller {
$x = '2eGriplW^*Jmf4';
$o = "[share author='".urlencode($p[0]['author']['xchan_name']).
"' profile='".$p[0]['author']['xchan_url'] .
"' avatar='".$p[0]['author']['xchan_photo_s'].
@@ -219,28 +219,28 @@ class Oep extends \Zotlabs\Web\Controller {
if($p[0]['title'])
$o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
$o .= $x;
$o .= $x;
$o .= "[/share]";
$o = bbcode($o);
$o = str_replace($x,bbcode($p[0]['body']),$o);
$ret['type'] = 'rich';
$w = (($maxwidth) ? $maxwidth : 640);
$h = (($maxheight) ? $maxheight : intval($w * 2 / 3));
$ret['html'] = '<div style="width: ' . $w . '; height: ' . $h . '; font-family: sans-serif,arial,freesans;" >' . $o . '</div>';
$ret['width'] = $w;
$ret['height'] = $h;
return $ret;
}
function oep_articles_reply($args) {
$ret = [];
$url = $args['url'];
$maxwidth = intval($args['maxwidth']);
@@ -251,7 +251,7 @@ class Oep extends \Zotlabs\Web\Controller {
$res = $matches[3];
}
if(! ($nick && $res))
return $ret;
return $ret;
$channel = channelx_by_nick($nick);
@@ -273,8 +273,8 @@ class Oep extends \Zotlabs\Web\Controller {
return $ret;
}
$r = q("select * from item
where item.uid = %d and item_type = %d
$r = q("select * from item
where item.uid = %d and item_type = %d
$sql_extra order by item.created desc",
intval($channel['channel_id']),
intval(ITEM_TYPE_ARTICLE)
@@ -294,7 +294,7 @@ class Oep extends \Zotlabs\Web\Controller {
$x = '2eGriplW^*Jmf4';
$o = "[share author='".urlencode($p[0]['author']['xchan_name']).
"' profile='".$p[0]['author']['xchan_url'] .
"' avatar='".$p[0]['author']['xchan_photo_s'].
@@ -305,71 +305,71 @@ class Oep extends \Zotlabs\Web\Controller {
if($p[0]['title'])
$o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
$o .= $x;
$o .= $x;
$o .= "[/share]";
$o = bbcode($o);
$o = str_replace($x,bbcode($p[0]['body']),$o);
$ret['type'] = 'rich';
$w = (($maxwidth) ? $maxwidth : 640);
$h = (($maxheight) ? $maxheight : intval($w * 2 / 3));
$ret['html'] = '<div style="width: ' . $w . '; height: ' . $h . '; font-family: sans-serif,arial,freesans;" >' . $o . '</div>';
$ret['width'] = $w;
$ret['height'] = $h;
return $ret;
}
function oep_mid_reply($args) {
$ret = array();
$url = $args['url'];
$maxwidth = intval($args['maxwidth']);
$maxheight = intval($args['maxheight']);
if(preg_match('#//(.*?)/(.*?)/(.*?)/(.*?)mid\=(.*?)(&|$)#',$url,$matches)) {
$chn = $matches[3];
$res = $matches[5];
}
if(! ($chn && $res))
return;
$c = q("select * from channel where channel_address = '%s' limit 1",
dbesc($chn)
);
if(! $c)
return;
if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_stream'))
return;
$sql_extra = item_permissions_sql($c[0]['channel_id']);
$p = q("select * from item where mid = '%s' and uid = %d $sql_extra limit 1",
dbesc($res),
intval($c[0]['channel_id'])
);
if(! $p)
return;
xchan_query($p,true);
$p = fetch_post_tags($p,true);
// This function can get tripped up if the item is already a reshare
// (the multiple share declarations do not parse cleanly if nested)
// (the multiple share declarations do not parse cleanly if nested)
// So build a template with a known nonsense string as the content, and then
// replace that known string with the actual rendered content, sending
// each content layer through bbcode() separately.
$x = '2eGriplW^*Jmf4';
$o = "[share author='".urlencode($p[0]['author']['xchan_name']).
"' profile='".$p[0]['author']['xchan_url'] .
"' avatar='".$p[0]['author']['xchan_photo_s'].
@@ -379,52 +379,52 @@ class Oep extends \Zotlabs\Web\Controller {
"' message_id='".$p[0]['mid']."']";
if($p[0]['title'])
$o .= '[b]'.$p[0]['title'].'[/b]'."\r\n";
$o .= $x;
$o .= $x;
$o .= "[/share]";
$o = bbcode($o);
$o = str_replace($x,bbcode($p[0]['body']),$o);
$ret['type'] = 'rich';
$w = (($maxwidth) ? $maxwidth : 640);
$h = (($maxheight) ? $maxheight : intval($w * 2 / 3));
$ret['html'] = '<div style="width: ' . $w . '; height: ' . $h . '; font-family: sans-serif,arial,freesans;" >' . $o . '</div>';
$ret['width'] = $w;
$ret['height'] = $h;
return $ret;
}
function oep_profile_reply($args) {
require_once('include/channel.php');
$url = $args['url'];
if(preg_match('#//(.*?)/(.*?)/(.*?)(/|\?|&|$)#',$url,$matches)) {
$chn = $matches[3];
}
if(! $chn)
return;
$c = channelx_by_nick($chn);
if(! $c)
return;
$maxwidth = intval($args['maxwidth']);
$maxheight = intval($args['maxheight']);
$width = 800;
$height = 375;
if($maxwidth) {
$width = $maxwidth;
$height = (375 / 800) * $width;
@@ -434,59 +434,59 @@ class Oep extends \Zotlabs\Web\Controller {
$width = (800 / 375) * $maxheight;
$height = $maxheight;
}
}
}
$ret = array();
$ret['type'] = 'rich';
$ret['width'] = intval($width);
$ret['height'] = intval($height);
$ret['html'] = get_zcard_embed($c,get_observer_hash(),array('width' => $width, 'height' => $height));
return $ret;
}
function oep_album_reply($args) {
$ret = array();
$url = $args['url'];
$maxwidth = intval($args['maxwidth']);
$maxheight = intval($args['maxheight']);
if(preg_match('|//(.*?)/(.*?)/(.*?)/album/|',$url,$matches)) {
$chn = $matches[3];
$res = basename($url);
}
if(! ($chn && $res))
return;
$c = q("select * from channel where channel_address = '%s' limit 1",
dbesc($chn)
);
if(! $c)
return;
if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_files'))
return;
$sql_extra = permissions_sql($c[0]['channel_id']);
$p = q("select resource_id from photo where album = '%s' and uid = %d and imgscale = 0 $sql_extra order by created desc limit 1",
dbesc($res),
intval($c[0]['channel_id'])
);
if(! $p)
return;
$res = $p[0]['resource_id'];
$r = q("select height, width, imgscale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by imgscale asc",
intval($c[0]['channel_id']),
dbesc($res)
);
if($r) {
foreach($r as $rr) {
$foundres = false;
@@ -494,62 +494,62 @@ class Oep extends \Zotlabs\Web\Controller {
continue;
if($maxwidth && $rr['width'] > $maxwidth)
continue;
$foundres = true;
$foundres = true;
break;
}
if($foundres) {
$ret['type'] = 'link';
$ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['imgscale'];
$ret['thumbnail_width'] = $rr['width'];
$ret['thumbnail_height'] = $rr['height'];
}
}
return $ret;
}
function oep_phototop_reply($args) {
$ret = array();
$url = $args['url'];
$maxwidth = intval($args['maxwidth']);
$maxheight = intval($args['maxheight']);
if(preg_match('|//(.*?)/(.*?)/(.*?)$|',$url,$matches)) {
$chn = $matches[3];
}
if(! $chn)
return;
$c = q("select * from channel where channel_address = '%s' limit 1",
dbesc($chn)
);
if(! $c)
return;
if(! perm_is_allowed($c[0]['channel_id'],get_observer_hash(),'view_files'))
return;
$sql_extra = permissions_sql($c[0]['channel_id']);
$p = q("select resource_id from photo where uid = %d and imgscale = 0 $sql_extra order by created desc limit 1",
intval($c[0]['channel_id'])
);
if(! $p)
return;
$res = $p[0]['resource_id'];
$r = q("select height, width, imgscale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by imgscale asc",
intval($c[0]['channel_id']),
dbesc($res)
);
if($r) {
foreach($r as $rr) {
$foundres = false;
@@ -557,42 +557,42 @@ class Oep extends \Zotlabs\Web\Controller {
continue;
if($maxwidth && $rr['width'] > $maxwidth)
continue;
$foundres = true;
$foundres = true;
break;
}
if($foundres) {
$ret['type'] = 'link';
$ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['imgscale'];
$ret['thumbnail_width'] = $rr['width'];
$ret['thumbnail_height'] = $rr['height'];
}
}
return $ret;
}
function oep_photo_reply($args) {
$ret = array();
$url = $args['url'];
$maxwidth = intval($args['maxwidth']);
$maxheight = intval($args['maxheight']);
if(preg_match('|//(.*?)/(.*?)/(.*?)/image/|',$url,$matches)) {
$chn = $matches[3];
$res = basename($url);
}
if(! ($chn && $res))
return;
$c = q("select * from channel where channel_address = '%s' limit 1",
dbesc($chn)
);
if(! $c)
return;
@@ -600,13 +600,13 @@ class Oep extends \Zotlabs\Web\Controller {
return;
$sql_extra = permissions_sql($c[0]['channel_id']);
$r = q("select height, width, imgscale, resource_id from photo where uid = %d and resource_id = '%s' $sql_extra order by imgscale asc",
intval($c[0]['channel_id']),
dbesc($res)
);
if($r) {
foreach($r as $rr) {
$foundres = false;
@@ -614,20 +614,20 @@ class Oep extends \Zotlabs\Web\Controller {
continue;
if($maxwidth && $rr['width'] > $maxwidth)
continue;
$foundres = true;
$foundres = true;
break;
}
if($foundres) {
$ret['type'] = 'link';
$ret['thumbnail_url'] = z_root() . '/photo/' . '/' . $rr['resource_id'] . '-' . $rr['imgscale'];
$ret['thumbnail_width'] = $rr['width'];
$ret['thumbnail_height'] = $rr['height'];
}
}
return $ret;
}
}

View File

@@ -180,7 +180,7 @@ class Photo extends \Zotlabs\Web\Controller {
$channel = channelx_by_n($r[0]['uid']);
// Now we'll see if we can access the photo
$e = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d $sql_extra LIMIT 1",
$e = q("SELECT * FROM photo WHERE resource_id = '%s' AND imgscale = %d LIMIT 1",
dbesc($photo),
intval($resolution)
);

447
Zotlabs/Module/Regate.php Normal file
View File

@@ -0,0 +1,447 @@
<?php
namespace Zotlabs\Module;
require_once('include/security.php');
/**
*
* @version 2.0.0
* @author hilmar runge
* @since 2020-03-03
* Check verification pin
* input field email address
* input field pin (told during register)
* check duty
* check startup and expire
* compare email address
* check pin
* limited tries to enter the correct pin/pass 2 handle via f2b
* on success create account and update register
*
*/
define ( 'REGISTER_AGREED', 0x0020 );
define ( 'REGISTER_DENIED', 0x0040 );
class Regate extends \Zotlabs\Web\Controller {
const MYP = 'ZAR'; //ZAR1x
const VERSION = '2.0.0';
function post() {
check_form_security_token_redirectOnErr('/', 'regate');
if ( argc() > 1 ) {
$did2 = hex2bin( substr( argv(1), 0, -1) );
$didx = substr( argv(1), -1 );
}
$msg = '';
$nextpage = '';
if ($did2) {
$nowhhmm = date('Hi');
$day = date('N');
$now = datetime_convert();
$ip = $_SERVER['REMOTE_ADDR'];
$isduty = zar_register_dutystate();
if (!$_SESSION['zar']['invite_in_progress'] && ($isduty['isduty'] !== false && $isduty['isduty'] != 1)) {
// normally, that should never happen here
// log suitable for fail2ban also
$logmsg = 'ZAR1230S Unexpected registration verification request for '
. get_config('system','sitename') . ' arrived from § ' . $ip . ' §';
zar_log($logmsg);
goaway(z_root());
}
// do we have a valid dId2 ?
if (($didx == 'a' && substr( $did2 , -2) == substr( base_convert( md5( substr( $did2, 1, -2) ),16 ,10), -2)) || ($didx == 'e') || ($didx == 'i')) {
// check startup and expiration via [=[register
$r = q("SELECT * FROM register WHERE reg_vital = 1 AND reg_did2 = '%s' ORDER BY reg_created DESC ",
dbesc($did2)
);
if ($r && count($r)) {
$r = $r[0];
// check timeframe
if ($r['reg_startup'] <= $now && $r['reg_expires'] >= $now) {
if (isset($_POST['resend']) && $didx == 'e') {
$re = q("SELECT * FROM register WHERE reg_vital = 1 AND reg_didx = 'e' AND reg_did2 = '%s' ORDER BY reg_created DESC ", dbesc($r['reg_did2']) );
if ($re) {
$re = $re[0];
$reonar = json_decode($re['reg_stuff'], true);
if ($reonar) {
$reonar['subject'] = 'Re,Fwd,' . $reonar['subject'];
$zm = zar_reg_mail($reonar);
$msg = (($zm) ? t('Email resent') : t('Email resend failed'));
zar_log((($zm) ? 'ZAR1238I' : 'ZAR1238E') . ' ' . $msg . ' ' . $r['reg_did2']);
info($msg);
return;
}
}
}
// check hash
if ( $didx == 'a' )
$acpin = (preg_match('/^[0-9]{6,6}$/', $_POST['acpin']) ? $_POST['acpin'] : false);
elseif ( $didx == 'e' )
$acpin = (preg_match('/^[0-9a-f]{24,24}$/', $_POST['acpin']) ? $_POST['acpin'] : false);
elseif ( $didx == 'i' )
$acpin = $r['reg_hash'];
else
$acpin = false;
if ( $acpin && ($r['reg_hash'] == $acpin )) {
$flags = $r['reg_flags'];
if (($flags & ACCOUNT_UNVERIFIED) == ACCOUNT_UNVERIFIED) {
// verification success
$msg_code = 'ZAR1237I';
$msg = t('Verification successful');
$reonar = json_decode( $r['reg_stuff'], true);
$reonar['valid'] = $now . ',' . $ip . ' ' . $did2 . ' ' . $msg_code . ' ' . $msg;
// clear flag
$flags &= $flags ^ ACCOUNT_UNVERIFIED;
// are we invited by the admin?
$isa = get_account_by_id($r['reg_uid']);
$isa = ($isa && ($isa['account_roles'] && ACCOUNT_ROLE_ADMIN));
// approve contra invite by admin
if ($isa && get_config('system','register_policy') == REGISTER_APPROVE) {
$flags &= $flags ^ ACCOUNT_PENDING;
}
// sth todo?
$vital = $flags == 0 ? 0 : 1;
// set flag
$flags |= REGISTER_AGREED;
zar_log($msg . ' ' . $did2 . ':flags' . $flags . ',rid' . $r['reg_id']);
q("START TRANSACTION");
$qu = q("UPDATE register SET reg_stuff = '%s', reg_vital = %d, reg_flags = %d "
." WHERE reg_id = %d ",
dbesc(json_encode($reonar)),
intval($vital),
intval($flags),
intval($r['reg_id'])
);
if (($flags & ACCOUNT_PENDING ) == ACCOUNT_PENDING) {
$nextpage = 'regate/' . bin2hex($did2) . $didx;
q("COMMIT");
}
elseif (($flags ^ REGISTER_AGREED) == 0) {
$cra = create_account_from_register([ 'reg_id' => $r['reg_id'] ]);
if ($cra['success']) {
q("COMMIT");
$msg = t('Account successfull created');
// zar_log($msg . ':' . print_r($cra, true));
zar_log('ZAR1238I ' . $msg . ' ' . $cra['account']['account_email']
. ' ' . $cra['account']['account_language']);
authenticate_success($cra['account'],null,true,false,true);
$nextpage = 'new_channel';
$auto_create = get_config('system', 'auto_channel_create', 1);
if($auto_create) {
$new_channel = ['success' => false];
// We do not reserve a channel_address before the registration is verified
// and possibly approved by the admin.
// If the provided channel_address has been claimed meanwhile,
// we will proceed to /new_channel.
if(isset($reonar['chan.did1']) && check_webbie([$reonar['chan.did1']])) {
// prepare channel creation
if($reonar['chan.name'])
set_aconfig($cra['account']['account_id'], 'register', 'channel_name', $reonar['chan.name']);
if($reonar['chan.did1'])
set_aconfig($cra['account']['account_id'], 'register', 'channel_address', $reonar['chan.did1']);
$permissions_role = get_config('system','default_permissions_role');
if($permissions_role)
set_aconfig($cra['account']['account_id'], 'register', 'permissions_role', $permissions_role);
// create channel
$new_channel = auto_channel_create($cra['account']['account_id']);
if($new_channel['success']) {
$channel_id = $new_channel['channel']['channel_id'];
change_channel($channel_id);
$nextpage = 'profiles/' . $channel_id;
$msg_code = 'ZAR1239I';
$msg = t('Channel successfull created') . ' ' . $did2;
}
}
if(!$new_channel['success']) {
$msg_code = 'ZAR1239E';
$msg = t('Automatic channel creation failed. Please create a channel.') . ' ' . $did2;
$nextpage = 'new_channel?name=' . $reonar['chan.name'];
}
zar_log($msg_code . ' ' . $msg . ' ' . $reonar['chan.did1'] . ' (' . $reonar['chan.name'] . ')');
}
unset($_SESSION['login_return_url']);
}
else {
q("ROLLBACK");
$msg_code = 'ZAR1238E';
$msg = t('Account creation error');
zar_log($msg_code . ' ' . $msg . ': ' . print_r($cra, true));
}
}
else {
// new flags implemented and not recognized or sth like
zar_log('ZAR1237D unexpected,' . $flags);
}
}
else {
// nothing to confirm
$msg_code = 'ZAR1236E';
$msg = t('Verify failed');
}
}
else {
$msg_code = 'ZAR1235E';
$msg = t('Token verification failed');
}
}
else {
$msg_code = 'ZAR1234W';
$msg = t('Request not inside time frame');
//info($r[0]['reg_startup'] . EOL . $r[0]['reg_expire'] );
}
}
else {
$msg_code = 'ZAR1232E';
$msg = t('Identity unknown');
zar_log($msg_code . ' ' . $msg . ':' . $did2 . $didx);
}
}
else {
$msg_code = 'ZAR1231E';
$msg = t('dId2 mistaken');
zar_log($msg_code . ' ' . $msg);
}
}
if ($msg > '') info($msg);
goaway( z_root() . '/' . $nextpage );
}
function get() {
if (argc() == 1) {
if(isset($_GET['reg_id'])) {
if ( preg_match('/^.{2,64}\@[a-z0-9.-]{4,32}\.[a-z]{2,12}$/', $_GET['reg_id'] ) ) {
// dId2 E email
goaway(z_root() . '/regate/' . bin2hex($_GET['reg_id']) . 'e' );
}
if ( preg_match('/^d{1,1}[0-9]{5,10}$/', $_GET['reg_id'] ) ) {
// dId2 A artifical & anonymous
goaway(z_root() . '/regate/' . bin2hex($_GET['reg_id']) . 'a' );
}
notice(t('Identity unknown') . EOL);
}
$o = replace_macros(get_markup_template('plain.tpl'), [
'$title' => t('Your Registration ID'),
'$now' => '<form action="regate" method="get"><input type="text" name="reg_id" class="form-control form-group"><button class="btn btn-primary float-right">Submit</button></form>'
]);
return $o;
}
$isduty = zar_register_dutystate();
$nowfmt = $isduty['nowfmt'];
$atform = $isduty['atform'];
if ($_SESSION['zar']['delayed']) {
$o = replace_macros(get_markup_template('regate_pre.tpl'), [
'$title' => t('Registration verification'),
'$now' => $nowfmt,
'$id' => $_SESSION['zar']['id'],
'$pin' => $_SESSION['zar']['pin'],
'$regdelay' => $_SESSION['zar']['regdelay'],
'$regexpire' => $_SESSION['zar']['regexpire'],
'$strings' => [
t('Hold on, you can start verification in'),
t('Please remember your verification token for ID'),
'',
t('Token validity')
]
]);
unset($_SESSION['zar']['delayed']);
return $o;
}
if (argc() < 2)
return;
$did2 = hex2bin( substr( argv(1), 0, -1) );
$didx = substr( argv(1), -1 );
$deny = argc() > 2 ? argv(2) : '';
$deny = preg_match('/^[0-9a-f]{8,8}$/', $deny) ? hex2bin($deny) : false;
$now = datetime_convert();
$ip = $_SERVER['REMOTE_ADDR'];
$pin = '';
if(isset($_SESSION['zar']['pin'])) {
$pin = $_SESSION['zar']['pin'];
unset($_SESSION['zar']['pin']);
}
// do we have a valid dId2 ?
if (($didx == 'a' && substr( $did2 , -2) == substr( base_convert( md5( substr( $did2, 1, -2) ),16 ,10), -2)) || ($didx == 'e') || ($didx == 'i')) {
$r = q("SELECT * FROM register WHERE reg_vital = 1 AND reg_didx = '%s' AND reg_did2 = '%s' ORDER BY reg_created DESC",
dbesc($didx),
dbesc($did2)
);
if ($r && count($r) && $r[0]['reg_flags'] &= (ACCOUNT_UNVERIFIED | ACCOUNT_PENDING)) {
$r = $r[0];
// provide a button in case
$resend = (($r['reg_didx'] == 'e') ? t('Resend email') : '');
// is still only instance admins intervention required?
if ($r['reg_flags'] == ACCOUNT_PENDING) {
$o = replace_macros(get_markup_template('regate_post.tpl'), [
'$title' => t('Registration status'),
'$id' => $did2,
'$strings' => [
t('Verification successful!'),
t('Your login ID is'),
t('After your account has been approved by our administrator you will be able to login with your login ID and your provided password.')
]
]);
}
else {
if ($deny) {
if (substr($r['reg_hash'],0,4) == $deny) {
zar_log('ZAR1134S email verfication denied ' . $did2);
$o = replace_macros(get_markup_template('plain.tpl'), [
'$title' => t('Registration request revoked'),
'$infos' => t('Sorry for any inconvience. Thank you for your response.')
]);
$reonar = json_decode( $r['reg_stuff'], true);
$reonar['deny'] = $now . ',' . $ip . ' ' . $did2 . ' ' . $msg;
$flags = ( $r['reg_flags'] &= ( $r['reg_flags'] ^ ACCOUNT_UNVERIFIED) )
| ( $r['reg_flags'] |= REGISTER_DENIED);
$rd = q("UPDATE register SET reg_stuff='%s', reg_vital=0, reg_flags=%d WHERE reg_id = %d ",
dbesc(json_encode($reonar)),
intval($flags),
intval($r['reg_id'])
);
}
else {
zar_log('ZAR1135E not awaited url parameter received');
goaway(z_root);
}
}
else {
if ( $r['reg_startup'] <= $now && $r['reg_expires'] >= $now) {
$o = replace_macros(get_markup_template('regate.tpl'), [
'$form_security_token' => get_form_security_token("regate"),
'$title' => t('Registration verification'),
'$desc' => t('Please enter your verification token for ID'),
'$email_extra' => (($didx === 'e') ? t('Please check your email!') : ''),
'$id' => $did2,
// we might consider to not provide $pin if a registration delay is configured
// and the pin turns out to be readable by bots
'$pin' => $pin,
'$did2' => bin2hex($did2) . $didx,
'$now' => $nowfmt,
'$atform' => $atform,
'$resend' => $resend,
'$submit' => t('Submit'),
'$acpin' => [ 'acpin', t('Verification token'),'','' ]
]);
}
else {
// expired ?
if ( $now > $r['reg_expires'] ) {
$rd = q("UPDATE register SET reg_vital = 0 WHERE reg_id = %d ",
intval($r['reg_id'])
);
$o = replace_macros(get_markup_template('plain.tpl'), [
'$infos' => t('ID expired'),
]);
return $o;
}
$email_extra = (($didx === 'e') ? t('Please check your email!') : '');
$o = replace_macros(get_markup_template('regate_pre.tpl'), [
'$title' => t('Registration verification'),
'$now' => $nowfmt,
'$id' => $did2,
'$countdown' => datetime_convert('UTC', 'UTC', $r['reg_startup'], 'c'),
'$strings' => [
t('Hold on, you can start verification in'),
t('You will require the verification token for ID'),
$email_extra
]
]);
}
}
}
}
else {
$msg = t('Unknown or expired ID');
zar_log('ZAR1132E ' . $msg . ':' . $did2 . ',' . $didx);
$o = replace_macros(get_markup_template('plain.tpl'), [
'$title' => $title,
'$now' => $nowfmt,
'$infos' => $msg
]);
}
}
else {
$msg = 'ZAR1131E ' . t('dId2 malformed');
// $log = ' from § ' . $ip . ' §' . ' (' . dbesc($did2) . ')';
zar_log($msg);
$o = replace_macros(get_markup_template('plain.tpl'), [
'$title' => $title,
'$now' => $nowfmt,
'$infos' => $msg
]);
}
return $o;
}
}

View File

@@ -1,25 +1,34 @@
<?php
namespace Zotlabs\Module;
use App;
use Zotlabs\Web\Controller;
require_once('include/security.php');
require_once('include/channel.php');
class Register extends Controller {
const MYP = 'ZAR'; // ZAR0x
const VERSION = '2.0.0';
function init() {
// ZAR0
$result = null;
$cmd = ((argc() > 1) ? argv(1) : '');
// Provide a stored request for somebody desiring a connection
// when they first need to register someplace. Once they've
// created a channel, we'll try to revive the connection request
// created a channel, we'll try to revive the connection request
// and process it.
if($_REQUEST['connect'])
$_SESSION['connect'] = $_REQUEST['connect'];
switch($cmd) {
case 'invite_check.json':
$result = check_account_invite($_REQUEST['invite_code']);
@@ -30,50 +39,161 @@ class Register extends Controller {
case 'password_check.json':
$result = check_account_password($_REQUEST['password1']);
break;
default:
default:
break;
}
if($result) {
json_return_and_die($result);
}
}
function post() {
check_form_security_token_redirectOnErr('/register', 'register');
$max_dailies = intval(get_config('system','max_daily_registrations'));
if($max_dailies) {
$r = q("select count(account_id) as total from account where account_created > %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('1 day')
);
if($r && $r[0]['total'] >= $max_dailies) {
notice( t('Maximum daily site registrations exceeded. Please try again tomorrow.') . EOL);
/**
* [hilmar:]
* It may happen, the posted form arrives in a strange fashion. With the control of the duty hours
* for registration, the input form was disabled at html. While receiving posted data, checks are
* required if all is on the right road (most posts are not accepted during off duty).
*
*/
$act = q("SELECT COUNT(*) AS act FROM account")[0]['act'];
$is247 = false;
$ip = $_SERVER['REMOTE_ADDR'];
$sameip = intval(get_config('system','register_sameip', 3));
$arr = $_POST;
$invite_code = ((x($arr,'invite_code')) ? notags(trim($arr['invite_code'])) : '');
$name = '';
$nick = '';
$email = ((x($arr,'email')) ? notags(punify(trim($arr['email']))) : '');
$password = ((x($arr,'password')) ? trim($arr['password']) : '');
$password2 = ((x($arr,'password2')) ? trim($arr['password2']) : '');
$register_msg = ((x($arr,'register_msg')) ? notags(trim($arr['register_msg'])) : '');
$reonar = [];
$auto_create = get_config('system','auto_channel_create', 1);
$duty = zar_register_dutystate();
if (!get_config('system', 'register_duty_jso')) {
// if not yet configured default to true
$duty = array( 'isduty' => true, 'atfrm' => '', 'nowfmt' => '');
}
if($auto_create) {
$name = escape_tags(trim($arr['name']));
$name_error = validate_channelname($name);
if($name_error) {
notice($name_error . EOL);
return $ret;
}
$nick = mb_strtolower(escape_tags(trim($arr['nickname'])));
if(!$nick) {
notice(t('Nickname is required.'));
return;
}
if($nick === 'sys') {
notice(t('Reserved nickname. Please choose another.') . EOL);
return;
}
if(check_webbie([$nick]) !== $nick) {
notice(t('Nickname has unsupported characters or is already being used on this site.') . EOL);
return;
}
}
if(! x($_POST,'tos')) {
notice( t('Please indicate acceptance of the Terms of Service. Registration failed.') . EOL);
$email_verify = get_config('system', 'verify_email');
if ($email_verify && !$email) {
notice(t('Email address required') . EOL);
return;
}
$policy = get_config('system','register_policy');
$email_verify = get_config('system','verify_email');
if ($email) {
$email_result = check_account_email($email);
if ($email_result['error']) {
if ($email_result['email_unverified']) {
goaway(z_root() . '/regate/' . bin2hex($email) . 'e');
}
return;
}
}
// case when an invited prepares the own account by supply own pw, accept tos, prepage channel (if auto)
if ($email && $invite_code) {
if ( preg_match('/^[a-z0-9]{12,12}$/', $invite_code ) ) {
$is247 = true;
}
}
if ($act > 0 && !$is247 && !$duty['isduty']) {
// normally (except very 1st timr after install), that should never arrive here (ie js hack or sth like)
// log suitable for f2b also
$logmsg = 'Unexpected registration request off duty';
notice($logmsg);
zar_log('ZAR0230S ' . $logmsg);
return;
}
if ($sameip) {
$f = q("SELECT COUNT(reg_atip) AS atip FROM register WHERE reg_vital = 1 AND reg_atip = '%s' ",
dbesc($ip)
);
if ($f && $f[0]['atip'] >= $sameip) {
$logmsg = 'ZAR0239S Exceeding same ip register request of ' . $sameip;
notice('Registrations from same IP exceeded.');
zar_log($logmsg);
return;
}
}
if (!$password) {
notice(t('No password provided') . EOL);
return;
}
if ($password !== $password2) {
notice(t('Passwords do not match') . EOL);
return;
}
$password_result = check_account_password($password);
if(!empty($password_result['error'])) {
$msg = $password_result['message'];
notice($msg);
zar_log($msg . ' ' . $did2);
return;
}
$salt = random_string(32);
$password = $salt . ',' . hash('whirlpool', $salt . $password);
// accept tos
if(! x($_POST,'tos')) {
// msg!
notice(t('Terms of Service not accepted') . EOL);
return;
}
$policy = get_config('system','register_policy');
$invonly = get_config('system','invitation_only');
$invalso = get_config('system','invitation_also');
switch($policy) {
case REGISTER_OPEN:
$flags = ACCOUNT_OK;
break;
case REGISTER_APPROVE:
$flags = ACCOUNT_BLOCKED | ACCOUNT_PENDING;
$flags = ACCOUNT_PENDING;
break;
default:
case REGISTER_CLOSED:
if(! is_site_admin()) {
@@ -83,164 +203,278 @@ class Register extends Controller {
$flags = ACCOUNT_BLOCKED;
break;
}
if($email_verify && $policy == REGISTER_OPEN)
$flags = $flags | ACCOUNT_UNVERIFIED;
if((! $_POST['password']) || ($_POST['password'] !== $_POST['password2'])) {
notice( t('Passwords do not match.') . EOL);
return;
}
$arr = $_POST;
if($email_verify && ($policy == REGISTER_OPEN || $policy == REGISTER_APPROVE))
$flags = ($flags | ACCOUNT_UNVERIFIED);
// $arr has $_POST;
$arr['account_flags'] = $flags;
$result = create_account($arr);
if(! $result['success']) {
notice($result['message']);
return;
}
require_once('include/security.php');
if($_REQUEST['name'])
set_aconfig($result['account']['account_id'],'register','channel_name',$_REQUEST['name']);
if($_REQUEST['nickname'])
set_aconfig($result['account']['account_id'],'register','channel_address',$_REQUEST['nickname']);
if($_REQUEST['permissions_role'])
set_aconfig($result['account']['account_id'],'register','permissions_role',$_REQUEST['permissions_role']);
$using_invites = intval(get_config('system','invitation_only'));
$num_invites = intval(get_config('system','number_invites'));
$invite_code = ((x($_POST,'invite_code')) ? notags(trim($_POST['invite_code'])) : '');
if($using_invites && $invite_code) {
q("delete from register where hash = '%s'", dbesc($invite_code));
// @FIXME - this also needs to be considered when using 'invites_remaining' in mod/invite.php
set_aconfig($result['account']['account_id'],'system','invites_remaining',$num_invites);
}
if($policy == REGISTER_OPEN ) {
if($email_verify) {
$res = verify_email_address($result);
}
else {
$res = send_register_success_email($result['email'],$result['password']);
}
if($res) {
if($invite_code) {
info( t('Registration successful. Continue to create your first channel...') . EOL ) ;
}
else {
info( t('Registration successful. Please check your email for validation instructions.') . EOL ) ;
$now = datetime_convert();
$well = false;
// s3
if ($invite_code) {
if ($invonly || $invalso) {
$reg = q("SELECT * from register WHERE reg_vital = 1 AND reg_didx = 'i' AND reg_hash = '%s'",
dbesc($invite_code)
);
if ($reg && count($reg) == 1) {
$reg = $reg[0];
if ($reg['reg_email'] == ($email)) {
if ($reg['reg_startup'] <= $now && $reg['reg_expires'] >= $now) {
if ($auto_create) {
$reonar['chan.name'] = $name;
$reonar['chan.did1'] = $nick;
}
q("UPDATE register set reg_pass = '%s', reg_stuff = '%s' WHERE reg_id = '%s'",
dbesc($password),
dbesc(json_encode($reonar)),
intval($reg['reg_id'])
);
$msg = t('Invitation code succesfully applied');
zar_log('ZAR0237I ' . $msg) . ', ' . $email;
// msg!
info($msg . EOL);
// the invitecode has verified us and we have all the info we need
// take the shortcut.
$_SESSION['zar']['invite_in_progress'] = true;
$mod = new Regate();
$_REQUEST['form_security_token'] = get_form_security_token("regate");
App::$argc = 2;
App::$argv[0] = 'regate';
App::$argv[1] = bin2hex($reg['reg_did2']) . 'i';
return $mod->post();
} else {
// msg!
notice(t('Invitation not in time or too late') . EOL);
return;
}
} else {
// no match email adr
$msg = t('Invitation email failed');
zar_log('ZAR0235S ' . $msg);
notice($msg . EOL);
return;
}
} else {
// no match invitecode
$msg = t('Invitation code failed') ;
zar_log('ZAR0234S ' . $msg);
notice( $msg . EOL);
return;
}
}
}
elseif($policy == REGISTER_APPROVE) {
$res = send_reg_approval_email($result);
if($res) {
info( t('Your registration is pending approval by the site owner.') . EOL ) ;
}
else {
notice( t('Your registration can not be processed.') . EOL);
}
goaway(z_root());
}
if($email_verify) {
goaway(z_root() . '/email_validation/' . bin2hex($result['email']));
}
// fall through and authenticate if no approvals or verifications were required.
authenticate_success($result['account'],null,true,false,true);
$new_channel = false;
$next_page = 'new_channel';
if(get_config('system','auto_channel_create')) {
$new_channel = auto_channel_create($result['account']['account_id']);
if($new_channel['success']) {
$channel_id = $new_channel['channel']['channel_id'];
change_channel($channel_id);
$next_page = '~';
}
else
$new_channel = false;
}
$x = get_config('system','workflow_register_next');
if($x) {
$next_page = $x;
$_SESSION['workflow'] = true;
}
unset($_SESSION['login_return_url']);
goaway(z_root() . '/' . $next_page);
}
function get() {
$registration_is = '';
$other_sites = '';
if(intval(get_config('system','register_policy')) === REGISTER_CLOSED) {
if(intval(get_config('system','directory_mode')) === DIRECTORY_MODE_STANDALONE) {
notice( t('Registration on this hub is disabled.') . EOL);
} else {
notice(t('Invitations are not available') . EOL);
return;
}
$mod = new Pubsites();
}
else {
if (!$invonly) {
$well = true;
}
else {
$msg = t('Registration on this hub is by invitation only') . EOL;
notice($msg);
zar_log('ZAR0233E ' . $msg);
return;
}
}
// check max daily registrations after we have dealt with the invitecode
if (self::check_reg_limits()['is']) {
notice('Max registrations per day exceeded.');
return;
}
if ($well) {
if($policy == REGISTER_OPEN || $policy == REGISTER_APPROVE ) {
$cfgdelay = get_config('system', 'register_delay', '0i');
$reg_delayed = calculate_adue( $cfgdelay );
$regdelay = (($reg_delayed) ? datetime_convert(date_default_timezone_get(), 'UTC', $reg_delayed['due']) : $now);
$cfgexpire = get_config('system', 'register_expire', '3d');
$reg_expires = calculate_adue( $cfgexpire );
$regexpire = (($reg_expires) ? datetime_convert(date_default_timezone_get(), 'UTC', $reg_expires['due']) : datetime_convert('UTC', 'UTC', 'now + 99 years'));
// handle an email request that will be verified or an ivitation associated with an email address
if ($email > '' && $email_verify) {
// enforce in case of icdone
$flags |= ACCOUNT_UNVERIFIED;
$empin = $pass2 = random_string(24);
$did2 = $email;
$didx = 'e';
push_lang(($reg['lang']) ? $reg['lang'] : App::$language);
$reonar['from'] = get_config('system', 'from_email');
$reonar['to'] = $email;
$reonar['subject'] = sprintf( t('Registration confirmation for %s'), get_config('system','sitename'));
$reonar['txttemplate']= replace_macros(get_intltext_template('register_verify_member.tpl'),
[
'$sitename' => get_config('system','sitename'),
'$siteurl' => z_root(),
'$email' => $email,
'$timeframe' => [$regdelay, $regexpire],
'$mail' => bin2hex($email) . 'e',
'$ko' => bin2hex(substr($empin,0,4)),
'$hash' => $empin
]
);
pop_lang();
zar_reg_mail($reonar);
} else {
// that is an anonymous request without email or with email not to verify
$acpin = $pass2 = rand(100000,999999);
$did2 = rand(10,99);
$didx = 'a';
// enforce delayed verify
$flags = ($flags | ACCOUNT_UNVERIFIED);
if ($email) {
$reonar['email.untrust'] = $email;
$reonar['email.comment'] = 'received, but no need for';
}
}
if ($auto_create) {
$reonar['chan.name'] = $name;
$reonar['chan.did1'] = $nick;
}
if ($policy == REGISTER_APPROVE) {
$reonar['msg'] = $register_msg;
}
$reg = q("INSERT INTO register ("
. "reg_flags,reg_didx,reg_did2,reg_hash,reg_created,reg_startup,reg_expires,"
. "reg_email,reg_pass,reg_lang,reg_atip,reg_stuff)"
. " VALUES (%d, '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s', '%s') ",
intval($flags),
dbesc($didx),
dbesc($did2),
dbesc($pass2),
dbesc($now),
dbesc($regdelay),
dbesc($regexpire),
dbesc($email),
dbesc($password),
dbesc(App::$language),
dbesc($ip),
dbesc(json_encode($reonar))
);
if ($didx == 'a') {
$lid = q("SELECT reg_id FROM register WHERE reg_vital = 1 AND reg_did2 = '%s' AND reg_pass = '%s' ",
dbesc($did2),
dbesc($password)
);
if ($lid && count($lid) == 1 ) {
$didnew = ( $lid[0]['reg_id'] . $did2 )
. ( substr( base_convert( md5( $lid[0]['reg_id'] . $did2 ), 16, 10 ),-2 ) );
$reg = q("UPDATE register SET reg_did2 = CONCAT('d','%s') WHERE reg_id = %d ",
dbesc($didnew), intval($lid[0]['reg_id'])
);
zar_log( 'ZAR0239A ' . t('New register request') . ' d' . $didnew . ', '
. $regdelay . ' - ' . $regexpire);
if($reg_delayed) {
// this could be removed to make registration harder
$_SESSION['zar']['id'] = 'd' . $didnew;
$_SESSION['zar']['pin'] = $pass2;
$_SESSION['zar']['delayed'] = true;
$_SESSION['zar']['regdelay'] = datetime_convert('UTC', 'UTC', $regdelay, 'c');
$_SESSION['zar']['regexpire'] = datetime_convert('UTC', 'UTC', $regexpire, 'c');
}
else {
$_SESSION['zar']['pin'] = $pass2;
}
goaway(z_root() . '/regate/' . bin2hex('d' . $didnew) . 'a' );
}
else {
$msg = t('Error creating dId A');
notice( $msg );
zar_log( 'ZAR0239D,' . $msg . ' ' . $did2);
}
}
goaway(z_root() . '/regate/' . bin2hex($email) . $didx );
}
}
}
function get() {
$registration_is = '';
$other_sites = '';
if(intval(get_config('system','register_policy')) === REGISTER_CLOSED) {
if(intval(get_config('system','directory_mode')) === DIRECTORY_MODE_STANDALONE) {
notice(t('Registration on this hub is disabled.') . EOL);
return;
}
$mod = new Pubsites();
return $mod->get();
}
if(intval(get_config('system','register_policy')) == REGISTER_APPROVE) {
$registration_is = t('Registration on this hub is by approval only.');
$other_sites = t('<a href="pubsites">Register at another affiliated hub.</a>');
$other_sites = '<a href="pubsites">' . t('Register at another affiliated hub in case when prefered') . '</a>';
}
$duty = zar_register_dutystate();
if (!get_config('system', 'register_duty_jso')) {
// if not yet configured default to true
$duty = array( 'isduty' => true, 'atfrm' => '', 'nowfmt' => '');
}
$invitations = false;
if(intval(get_config('system','invitation_only'))) {
$invitations = true;
$registration_is = t('Registration on this hub is by invitation only.');
$other_sites = t('<a href="pubsites">Register at another affiliated hub.</a>');
}
$max_dailies = intval(get_config('system','max_daily_registrations'));
if($max_dailies) {
$r = q("select count(account_id) as total from account where account_created > %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('1 day')
);
if($r && $r[0]['total'] >= $max_dailies) {
logger('max daily registrations exceeded.');
notice( t('This site has exceeded the number of allowed daily account registrations. Please try again tomorrow.') . EOL);
return;
}
$other_sites = '<a href="pubsites">' . t('Register at another affiliated hub') . '</a>';
} elseif (intval(get_config('system','invitation_also'))) {
$invitations = true;
}
$privacy_role = ((x($_REQUEST,'permissions_role')) ? $_REQUEST['permissions_role'] : "");
$perm_roles = \Zotlabs\Access\PermissionRoles::roles();
$opal = self::check_reg_limits();
if ( $opal['is'])
$duty['atform'] = 'disabled';
// Configurable terms of service link
$tosurl = get_config('system','tos_url');
if(! $tosurl)
$tosurl = z_root() . '/help/TermsOfService';
$toslink = '<a href="' . $tosurl . '" target="_blank">' . t('Terms of Service') . '</a>';
// Configurable whether to restrict age or not - default is based on international legal requirements
// This can be relaxed if you are on a restricted server that does not share with public servers
if(get_config('system','no_age_restriction')) {
$label_tos = sprintf( t('I accept the %s for this website'), $toslink);
}
@@ -253,50 +487,96 @@ class Register extends Controller {
}
$enable_tos = 1 - intval(get_config('system','no_termsofservice'));
$email = array('email', t('Your email address'), ((x($_REQUEST,'email')) ? strip_tags(trim($_REQUEST['email'])) : ""));
$password = array('password', t('Choose a password'), '');
$password2 = array('password2', t('Please re-enter your password'), '');
$invite_code = array('invite_code', t('Please enter your invitation code'), ((x($_REQUEST,'invite_code')) ? strip_tags(trim($_REQUEST['invite_code'])) : ""));
$name = array('name', t('Your Name'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Real names are preferred.'));
$nickhub = '@' . str_replace(array('http://','https://','/'), '', get_config('system','baseurl'));
$nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), sprintf( t('Your nickname will be used to create an easy to remember channel address e.g. nickname%s'), $nickhub));
$role = array('permissions_role' , t('Channel role and privacy'), ($privacy_role) ? $privacy_role : 'social', t('Select a channel permission role for your usage needs and privacy requirements.') . ' <a href="help/member/member_guide#Channel_Permission_Roles" target="_blank">' . t('Read more about channel permission roles') . '</a>',$perm_roles);
$tos = array('tos', $label_tos, '', '', array(t('no'),t('yes')));
$auto_create = (get_config('system','auto_channel_create') ? true : false);
$default_role = get_config('system','default_permissions_role');
$auto_create = get_config('system', 'auto_channel_create', 1);
$email_verify = get_config('system','verify_email');
require_once('include/bbcode.php');
$o = replace_macros(get_markup_template('register.tpl'), array(
$emailval = ((x($_REQUEST,'email')) ? strip_tags(trim($_REQUEST['email'])) : "");
$email = ['email',
t('Your email address'),
$emailval,
(($email_verify) ? t('Required') : t('Optional')),
(($email_verify) ? '*' : ''),
$duty['atform']
];
$password = array('password', t('Choose a password'), '', '', '', $duty['atform']);
$password2 = array('password2', t('Please re-enter your password'), '', '', '', $duty['atform']);
$invite_code = array('invite_code', t('Please enter your invitation code'), ((x($_REQUEST,'invite_code')) ? strip_tags(trim($_REQUEST['invite_code'])) : ""));
$name = array('name', t('Your name'), ((x($_REQUEST,'name')) ? $_REQUEST['name'] : ''), t('Real name is preferred'), '', '', $duty['atform']);
$nickhub = '@' . str_replace(array('http://','https://','/'), '', get_config('system','baseurl'));
$nickname = array('nickname', t('Choose a short nickname'), ((x($_REQUEST,'nickname')) ? $_REQUEST['nickname'] : ''), t('Your nickname will be used to create an easy to remember channel address'), '', '', $duty['atform']);
$tos = array('tos', $label_tos, ((x($_REQUEST,'tos')) ? $_REQUEST['tos'] : ''), '', [t('No'),t('Yes')], $duty['atform']);
$register_msg = ['register_msg', t('Why do you want to join this hub?'), ((x($_REQUEST,'register_msg')) ? $_REQUEST['register_msg'] : ''), t('This will help to review your registration')];
require_once('include/bbcode.php');
$o = replace_macros(get_markup_template('register.tpl'), array(
'$form_security_token' => get_form_security_token("register"),
'$title' => t('Registration'),
'$reg_is' => $registration_is,
'$register_msg' => $register_msg,
'$registertext' => bbcode(get_config('system','register_text')),
'$other_sites' => $other_sites,
'$msg' => $opal['msg'],
'$invitations' => $invitations,
'$invite_code' => $invite_code,
'$haveivc' => t('I have an invite code'),
'$now' => $duty['nowfmt'],
'$atform' => $duty['atform'],
'$auto_create' => $auto_create,
'$name' => $name,
'$role' => $role,
'$default_role' => $default_role,
'$nickname' => $nickname,
'$enable_tos' => $enable_tos,
'$tos' => $tos,
'$email' => $email,
'$validate' => $validate,
'$validate_link'=> $validate_link,
'$validate_here'=> $validate_here,
'$pass1' => $password,
'$pass2' => $password2,
'$submit' => t('Register'),
'$verify_note' => (($email_verify) ? t('This site requires email verification. After completing this form, please check your email for further instructions.') : ''),
'$nickhub' => $nickhub
));
return $o;
}
function check_reg_limits() {
// check against register, account
$rear = array( 'is' => false, 'rn' => 0, 'an' => 0, 'msg' => '' );
$max_dailies = intval(get_config('system', 'max_daily_registrations', 50));
if ($max_dailies) {
$r = q("SELECT COUNT(reg_id) AS nr FROM register WHERE reg_vital = 1 AND reg_created > %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('1 day')
);
$rear['is'] = ( $r && $r[0]['nr'] >= $max_dailies ) ? true : false;
$rear['rn'] = $r[0]['nr'];
if (!$rear['is']) {
$r = q("SELECT COUNT(account_id) AS nr FROM account WHERE account_created > %s - INTERVAL %s",
db_utcnow(), db_quoteinterval('1 day')
);
$rear['is'] = ( $r && ($r[0]['nr'] + $rear['rn']) >= $max_dailies ) ? true : false;
$rear['ra'] = $r[0]['nr'];
}
if ( $rear['is']) {
$rear['msg'] = t('This site has exceeded the number of allowed daily account registrations.');
zar_log('ZAR0333W ' . $rear['msg']);
$rear['is'] = true;
}
}
return $rear;
}
}

View File

@@ -58,7 +58,7 @@ class Search extends Controller {
$o .= search($search, 'search-box', '/search', ((local_channel()) ? true : false));
if (local_channel() && strpos($search, 'https://') === 0 && !$update && !$load) {
$j = Activity::fetch($search, App::get_channel());
$j = Activity::fetch(punify($search), App::get_channel());
if ($j) {
$AS = new ActivityStreams($j);
if ($AS->is_valid()) {
@@ -101,7 +101,7 @@ class Search extends Controller {
}
// look for a naked webbie
if (strpos($search, '@') !== false) {
if (strpos($search,'@') !== false && strpos($search,'http') !== 0) {
goaway(z_root() . '/directory' . '?f=1&navsearch=1&search=' . $search);
}

View File

@@ -15,20 +15,23 @@ class Account {
$account = \App::get_account();
if($email != $account['account_email']) {
if(! validate_email($email))
$errs[] = t('Not valid email.');
$adm = trim(get_config('system','admin_email'));
if(($adm) && (strcasecmp($email,$adm) == 0)) {
$errs[] = t('Protected email address. Cannot change to that email.');
$email = \App::$account['account_email'];
}
if(! $errs) {
$r = q("update account set account_email = '%s' where account_id = %d",
dbesc($email),
intval($account['account_id'])
);
if(! $r)
$errs[] = t('System failure storing new email. Please try again.');
// a DId2 not an email addr does not allow to change to email addr
if (strpos($email, '@') > 0) {
if(! validate_email($email))
$errs[] = t('Not valid email.');
$adm = trim(get_config('system','admin_email'));
if(($adm) && (strcasecmp($email,$adm) == 0)) {
$errs[] = t('Protected email address. Cannot change to that email.');
$email = \App::$account['account_email'];
}
if(! $errs) {
$r = q("update account set account_email = '%s' where account_id = %d",
dbesc($email),
intval($account['account_id'])
);
if(! $r)
$errs[] = t('System failure storing new email. Please try again.');
}
}
}
@@ -92,6 +95,7 @@ class Account {
call_hooks('account_settings', $account_settings);
$email = \App::$account['account_email'];
$attremail = (!strpos($email, '@')) ? 'disabled="disabled"' : '';
$tpl = get_markup_template("settings_account.tpl");
$o .= replace_macros($tpl, array(
@@ -101,7 +105,7 @@ class Account {
'$password1'=> array('npassword', t('Enter New Password'), '', ''),
'$password2'=> array('confirm', t('Confirm New Password'), '', t('Leave password fields blank unless changing')),
'$submit' => t('Submit'),
'$email' => array('email', t('Email Address:'), $email, ''),
'$email' => array('email', t('DId2 or Email Address:'), $email, '', '', $attremail),
'$removeme' => t('Remove Account'),
'$removeaccount' => t('Remove this account including all its channels'),
'$account_settings' => $account_settings

View File

@@ -47,7 +47,6 @@ class Sse extends Controller {
self::$vnotify = get_pconfig(self::$uid, 'system', 'vnotify');
$sys = get_sys_channel();
$sleep_seconds = 3;
self::$sse_enabled = get_config('system', 'sse_enabled', 0);

View File

@@ -6,6 +6,7 @@ use App;
use Zotlabs\Lib\Apps;
use Zotlabs\Web\Controller;
use Zotlabs\Lib\Enotify;
use Zotlabs\Lib\XConfig;
class Sse_bs extends Controller {
@@ -101,12 +102,13 @@ class Sse_bs extends Controller {
self::bs_files(),
self::bs_mail(),
self::bs_all_events(),
self::bs_register()
self::bs_register(),
self::bs_info_notice()
);
set_xconfig(self::$ob_hash, 'sse', 'timestamp', datetime_convert());
set_xconfig(self::$ob_hash, 'sse', 'notifications', []); // reset the cache
set_xconfig(self::$ob_hash, 'sse', 'language', App::$language);
XConfig::Set(self::$ob_hash, 'sse', 'notifications', []);
XConfig::Set(self::$ob_hash, 'sse', 'timestamp', datetime_convert());
XConfig::Set(self::$ob_hash, 'sse', 'language', App::$language);
json_return_and_die($result);
}
@@ -686,12 +688,15 @@ class Sse_bs extends Controller {
if(! self::$uid && ! is_site_admin())
return $result;
$policy = intval(get_config('system','register_policy'));
if(($policy & REGISTER_APPROVE) != REGISTER_APPROVE)
return $result;
if(! (self::$vnotify & VNOTIFY_REGISTER))
return $result;
$r = q("SELECT account_email, account_created from account where (account_flags & %d) > 0",
intval(ACCOUNT_PENDING)
);
$r = get_pending_accounts();
if($r) {
foreach($r as $rr) {
$result['register']['notifications'][] = Enotify::format_register($rr);
@@ -703,4 +708,22 @@ class Sse_bs extends Controller {
}
function bs_info_notice() {
$result['notice']['notifications'] = [];
$result['info']['notifications'] = [];
$r = XConfig::Get(self::$ob_hash, 'sse', 'notifications', []);
if(isset($r['notice']))
$result['notice']['notifications'] = $r['notice']['notifications'];
if(isset($r['info']))
$result['info']['notifications'] = $r['info']['notifications'];
return $result;
}
}

View File

@@ -15,17 +15,17 @@ class Suggest extends \Zotlabs\Web\Controller {
if(! Apps::system_app_installed(local_channel(), 'Suggest Channels'))
return;
if(x($_GET,'ignore')) {
q("insert into xign ( uid, xchan ) values ( %d, '%s' ) ",
intval(local_channel()),
dbesc($_GET['ignore'])
);
}
}
function get() {
if(! local_channel()) {
@@ -45,22 +45,22 @@ class Suggest extends \Zotlabs\Web\Controller {
$o = '';
nav_set_selected('Suggest Channels');
$_SESSION['return_url'] = z_root() . '/' . \App::$cmd;
$r = suggestion_query(local_channel(),get_observer_hash());
if(! $r) {
info( t('No suggestions available. If this is a new site, please try again in 24 hours.'));
return;
}
$arr = array();
foreach($r as $rr) {
$connlnk = z_root() . '/follow/?url=' . $rr['xchan_addr'];
$connlnk = z_root() . '/follow?f=&url=' . $rr['xchan_addr'];
$arr[] = array(
'url' => chanlink_url($rr['xchan_url']),
'common' => $rr['total'],
@@ -73,15 +73,15 @@ class Suggest extends \Zotlabs\Web\Controller {
'ignore' => t('Ignore/Hide')
);
}
$o = replace_macros(get_markup_template('suggest_page.tpl'),array(
'$title' => t('Channel Suggestions'),
'$entries' => $arr
));
return $o;
}
}

View File

@@ -20,6 +20,8 @@ class Wfinger extends \Zotlabs\Web\Controller {
$scheme = 'https';
elseif(x($_SERVER,'SERVER_PORT') && (intval($_SERVER['SERVER_PORT']) == 443))
$scheme = 'https';
elseif(x($_SERVER,'HTTP_X_FORWARDED_PROTO') && ($_SERVER['HTTP_X_FORWARDED_PROTO'] == 'https'))
$scheme = 'https';
$zot = intval($_REQUEST['zot']);

View File

@@ -127,7 +127,6 @@ class Wiki extends Controller {
$resource_id = argv(4);
$w = NativeWiki::get_wiki($owner['channel_id'],$observer_hash,$resource_id);
// $w = NativeWiki::get_wiki($owner,$observer_hash,$resource_id);
if(! $w['htmlName']) {
notice(t('Error retrieving wiki') . EOL);
@@ -218,12 +217,12 @@ class Wiki extends Controller {
'$name' => t('Name'),
'$type' => t('Type'),
'$unlocked' => t('Any&nbsp;type'),
'$lockstate' => $x['lockstate'],
'$acl' => $x['acl'],
'$allow_cid' => $x['allow_cid'],
'$allow_gid' => $x['allow_gid'],
'$deny_cid' => $x['deny_cid'],
'$deny_gid' => $x['deny_gid'],
'$lockstate' => (x($x,'lockstate') ? $x['lockstate'] : ''),
'$acl' => (x($x,'acl') ? $x['acl'] : ''),
'$allow_cid' => (x($x,'allow_cid') ? $x['allow_cid'] : ''),
'$allow_gid' => (x($x,'allow_gid') ? $x['allow_gid'] : ''),
'$deny_cid' => (x($x,'deny_cid') ? $x['deny_cid'] : ''),
'$deny_gid' => (x($x,'deny_gid') ? $x['deny_gid'] : ''),
'$typelock' => array('typelock', t('Lock content type'), '', '', array(t('No'), t('Yes'))),
'$notify' => array('postVisible', t('Create a status post for this wiki'), '', '', array(t('No'), t('Yes'))),
'$edit_wiki_name' => t('Edit Wiki Name')
@@ -508,7 +507,7 @@ class Wiki extends Controller {
notice( t('Wiki created, but error creating Home page.'));
goaway(z_root() . '/wiki/' . $nick . '/' . NativeWiki::name_encode($wiki['urlName']));
}
NativeWiki::sync_a_wiki_item($owner['channel_id'],$homePage['item_id'],$r['item']['resource_id']);
NativeWiki::sync_a_wiki_item($owner['channel_id'], $homePage['item_id'], $r['item']['resource_id']);
goaway(z_root() . '/wiki/' . $nick . '/' . NativeWiki::name_encode($wiki['urlName']) . '/' . NativeWiki::name_encode($homePage['page']['urlName']));
}
else {
@@ -542,7 +541,6 @@ class Wiki extends Controller {
}
$wiki = NativeWiki::exists_by_name($owner['channel_id'], $arr['urlName']);
if($wiki['resource_id']) {
$arr['resource_id'] = $wiki['resource_id'];
@@ -552,7 +550,7 @@ class Wiki extends Controller {
$r = NativeWiki::update_wiki($owner['channel_id'], $observer_hash, $arr, $acl);
if($r['success']) {
NativeWiki::sync_a_wiki_item($owner['channel_id'],$r['item_id'],$r['item']['resource_id']);
NativeWiki::sync_a_wiki_item($owner['channel_id'], $r['item_id'], $r['item']['resource_id']);
goaway(z_root() . '/wiki/' . $nick);
}
else {
@@ -576,7 +574,7 @@ class Wiki extends Controller {
$resource_id = $_POST['resource_id'];
$deleted = NativeWiki::delete_wiki($owner['channel_id'],$observer_hash,$resource_id);
if ($deleted['success']) {
NativeWiki::sync_a_wiki_item($owner['channel_id'],$deleted['item_id'],$resource_id);
NativeWiki::sync_a_wiki_item($owner['channel_id'], 0, $resource_id);
json_return_and_die(array('message' => '', 'success' => true));
}
else {
@@ -611,18 +609,17 @@ class Wiki extends Controller {
}
$page = NativeWikiPage::create_page($owner['channel_id'],$observer_hash, $name, $resource_id, $mimetype);
if($page['item_id']) {
$commit = NativeWikiPage::commit(array(
$commit = NativeWikiPage::commit([
'commit_msg' => t('New page created'),
'resource_id' => $resource_id,
'channel_id' => $owner['channel_id'],
'observer_hash' => $observer_hash,
'pageUrlName' => $name
));
]);
if($commit['success']) {
NativeWiki::sync_a_wiki_item($owner['channel_id'],$commit['item_id'],$resource_id);
NativeWiki::sync_a_wiki_item($owner['channel_id'], $commit['item_id'], $resource_id);
//json_return_and_die(array('url' => '/' . argv(0) . '/' . argv(1) . '/' . urlencode($page['wiki']['urlName']) . '/' . urlencode($page['page']['urlName']), 'success' => true));
json_return_and_die(array('url' => '/' . argv(0) . '/' . argv(1) . '/' . $page['wiki']['urlName'] . '/' . $page['page']['urlName'], 'success' => true));
}
@@ -680,20 +677,25 @@ class Wiki extends Controller {
json_return_and_die(array('success' => false));
}
$saved = NativeWikiPage::save_page(array('channel_id' => $owner['channel_id'], 'observer_hash' => $observer_hash, 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName, 'content' => $content));
$saved = NativeWikiPage::save_page([
'channel_id' => $owner['channel_id'],
'observer_hash' => $observer_hash,
'resource_id' => $resource_id,
'pageUrlName' => $pageUrlName,
'content' => $content
]);
if($saved['success']) {
$commit = NativeWikiPage::commit(array(
$commit = NativeWikiPage::commit([
'commit_msg' => $commitMsg,
'pageUrlName' => $pageUrlName,
'resource_id' => $resource_id,
'channel_id' => $owner['channel_id'],
'observer_hash' => $observer_hash,
'revision' => (-1)
));
]);
if($commit['success']) {
NativeWiki::sync_a_wiki_item($owner['channel_id'],$commit['item_id'],$resource_id);
NativeWiki::sync_a_wiki_item($owner['channel_id'], $commit['item_id'], $resource_id);
json_return_and_die(array('message' => 'Wiki git repo commit made', 'success' => true , 'content' => $content));
}
else {
@@ -738,9 +740,9 @@ class Wiki extends Controller {
if ($pageUrlName === 'Home') {
json_return_and_die(array('message' => t('Cannot delete Home'),'success' => false));
}
// Determine if observer has permission to delete pages
// currently just allow page owner
if((! local_channel()) || (local_channel() != $owner['channel_id'])) {
logger('Wiki write permission denied. ' . EOL);
json_return_and_die(array('success' => false));
@@ -752,9 +754,14 @@ class Wiki extends Controller {
json_return_and_die(array('success' => false));
}
$deleted = NativeWikiPage::delete_page(array('channel_id' => $owner['channel_id'], 'observer_hash' => $observer_hash, 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName));
$deleted = NativeWikiPage::delete_page([
'channel_id' => $owner['channel_id'],
'observer_hash' => $observer_hash,
'resource_id' => $resource_id,
'pageUrlName' => $pageUrlName
]);
if($deleted['success']) {
NativeWiki::sync_a_wiki_item($owner['channel_id'],$commit['item_id'],$resource_id);
NativeWiki::sync_a_wiki_item($owner['channel_id'], 0, $resource_id);
json_return_and_die(array('message' => 'Wiki git repo commit made', 'success' => true));
}
else {
@@ -768,18 +775,25 @@ class Wiki extends Controller {
$resource_id = $_POST['resource_id'];
$pageUrlName = $_POST['name'];
$commitHash = $_POST['commitHash'];
// Determine if observer has permission to revert pages
// Determine if observer has permission to revert pages
$perms = NativeWiki::get_permissions($resource_id, intval($owner['channel_id']), $observer_hash);
if(! $perms['write']) {
logger('Wiki write permission denied.' . EOL);
json_return_and_die(array('success' => false));
}
$reverted = NativeWikiPage::revert_page(array('channel_id' => $owner['channel_id'], 'observer_hash' => $observer_hash, 'commitHash' => $commitHash, 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName));
$reverted = NativeWikiPage::revert_page([
'channel_id' => $owner['channel_id'],
'observer_hash' => $observer_hash,
'commitHash' => $commitHash,
'resource_id' => $resource_id,
'pageUrlName' => $pageUrlName
]);
if($reverted['success']) {
json_return_and_die(array('content' => $reverted['content'], 'message' => '', 'success' => true));
} else {
}
else {
json_return_and_die(array('content' => '', 'message' => 'Error reverting page', 'success' => false));
}
}
@@ -826,18 +840,23 @@ class Wiki extends Controller {
json_return_and_die(array('success' => false));
}
$renamed = NativeWikiPage::rename_page(array('channel_id' => $owner['channel_id'], 'observer_hash' => $observer_hash, 'resource_id' => $resource_id, 'pageUrlName' => $pageUrlName, 'pageNewName' => $pageNewName));
$renamed = NativeWikiPage::rename_page([
'channel_id' => $owner['channel_id'],
'observer_hash' => $observer_hash,
'resource_id' => $resource_id,
'pageUrlName' => $pageUrlName,
'pageNewName' => $pageNewName
]);
if($renamed['success']) {
$commit = NativeWikiPage::commit(array(
$commit = NativeWikiPage::commit([
'channel_id' => $owner['channel_id'],
'commit_msg' => 'Renamed ' . NativeWiki::name_decode($pageUrlName) . ' to ' . $renamed['page']['htmlName'],
'resource_id' => $resource_id,
'observer_hash' => $observer_hash,
'pageUrlName' => $pageNewName
));
]);
if($commit['success']) {
NativeWiki::sync_a_wiki_item($owner['channel_id'],$commit['item_id'],$resource_id);
NativeWiki::sync_a_wiki_item($owner['channel_id'], $commit['item_id'], $resource_id);
json_return_and_die(array('name' => $renamed['page'], 'message' => 'Wiki git repo commit made', 'success' => true));
}
else {

View File

@@ -330,6 +330,8 @@ class Comanche {
$name = str_replace($mtch[0], '', $name);
}
}
else
$var = [];
if($channel_id) {
$m = menu_fetch($name, $channel_id, get_observer_hash());
@@ -408,7 +410,8 @@ class Comanche {
}
//emit the block
$o .= (($var['wrap'] == 'none') ? '' : '<div class="' . $class . '">');
$wrap = (! x($var, 'wrap') || $var['wrap'] == 'none' ? false : true);
$o .= ($wrap ? '' : '<div class="' . $class . '">');
if($r[0]['title'] && trim($r[0]['body']) != '$content') {
$o .= '<h3>' . $r[0]['title'] . '</h3>';
@@ -421,7 +424,7 @@ class Comanche {
$o .= prepare_text($r[0]['body'], $r[0]['mimetype']);
}
$o .= (($var['wrap'] == 'none') ? '' : '</div>');
$o .= ($wrap ? '' : '</div>');
}
}

View File

@@ -8,16 +8,16 @@ use App;
class SmartyTemplate implements TemplateEngine {
static $name ="smarty3";
public function __construct() {
// Cannot use get_config() here because it is called during installation when there is no DB.
// FIXME: this may leak private information such as system pathnames.
$basecompiledir = ((array_key_exists('smarty3_folder', App::$config['system']))
$basecompiledir = ((array_key_exists('smarty3_folder', App::$config['system']))
? App::$config['system']['smarty3_folder'] : '');
if (! $basecompiledir) {
$basecompiledir = str_replace('Zotlabs','',dirname(__dir__)) . "/" . TEMPLATE_BUILD_PATH;
$basecompiledir = str_replace('Zotlabs','',dirname(__dir__)) . TEMPLATE_BUILD_PATH;
}
if (! is_dir($basecompiledir)) {
@os_mkdir(TEMPLATE_BUILD_PATH, STORAGE_DEFAULT_PERMISSIONS, true);
@@ -30,7 +30,7 @@ class SmartyTemplate implements TemplateEngine {
}
App::$config['system']['smarty3_folder'] = $basecompiledir;
}
// TemplateEngine interface
public function replace_macros($s, $r) {
@@ -52,9 +52,9 @@ class SmartyTemplate implements TemplateEngine {
}
$s->assign($key, $value);
}
return $s->parsed($template);
return $s->parsed($template);
}
public function get_markup_template($file, $root = '') {
$template_file = theme_include($file, $root);
if ($template_file) {
@@ -62,7 +62,7 @@ class SmartyTemplate implements TemplateEngine {
$template->filename = $template_file;
return $template;
}
}
return EMPTY_STR;
}
@@ -84,7 +84,7 @@ class SmartyTemplate implements TemplateEngine {
$template = new SmartyInterface();
$template->filename = $template_file;
return $template;
}
}
return "";
}

View File

@@ -125,10 +125,10 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
* Array with the values for the authenticated channel.
* @return bool
*/
protected function setAuthenticated($r) {
$this->channel_name = $r['channel_address'];
$this->channel_id = $r['channel_id'];
$this->channel_hash = $this->observer = $r['channel_hash'];
protected function setAuthenticated($channel) {
$this->channel_name = $channel['channel_address'];
$this->channel_id = $channel['channel_id'];
$this->channel_hash = $this->observer = $channel['channel_hash'];
if ($this->observer) {
$r = q("select * from xchan where xchan_hash = '%s' limit 1",
@@ -139,8 +139,8 @@ class BasicAuth extends DAV\Auth\Backend\AbstractBasic {
}
}
$_SESSION['uid'] = $r['channel_id'];
$_SESSION['account_id'] = $r['channel_account_id'];
$_SESSION['uid'] = $channel['channel_id'];
$_SESSION['account_id'] = $channel['channel_account_id'];
$_SESSION['authenticated'] = true;
return true;
}

15
Zotlabs/Update/_1244.php Normal file
View File

@@ -0,0 +1,15 @@
<?php
namespace Zotlabs\Update;
require_once('include/account.php');
class _1244 {
function run() {
return verify_register_scheme();
}
}

29
Zotlabs/Update/_1245.php Normal file
View File

@@ -0,0 +1,29 @@
<?php
namespace Zotlabs\Update;
class _1245 {
function run() {
if(ACTIVE_DBTYPE == DBTYPE_MYSQL) {
return UPDATE_SUCCESS;
}
if(ACTIVE_DBTYPE == DBTYPE_POSTGRES) {
q("START TRANSACTION");
$r = dbq("create index hubloc_hash on hubloc (hubloc_hash)");
if($r) {
q("COMMIT");
return UPDATE_SUCCESS;
}
q("ROLLBACK");
return UPDATE_FAILED;
}
}
}

View File

@@ -250,7 +250,7 @@ class HTTPSig {
static function convertKey($key) {
if(strstr($key,'RSA ')) {
return rsatopem($key);
return Keyutils::rsaToPem($key);
}
elseif(substr($key,0,5) === 'data:') {
return Keyutils::convertSalmonKey($key);

View File

@@ -29,34 +29,44 @@ class Session {
/*
* Set our session storage functions.
*/
if($this->custom_handler) {
/* Custom handler (files, memached, redis..) */
$session_save_handler = strval(get_config('system', 'session_save_handler', Null));
$session_save_path = strval(get_config('system', 'session_save_path', Null));
$session_gc_probability = intval(get_config('system', 'session_gc_probability', 1));
$session_gc_divisor = intval(get_config('system', 'session_gc_divisor', 100));
if(!$session_save_handler || !$session_save_path) {
logger('Session save handler or path not set.',LOGGER_NORMAL,LOG_ERR);
if(is_null($session_save_handler) || is_null($session_save_path)) {
logger('Session save handler or path not set', LOGGER_NORMAL, LOG_ERR);
}
else {
ini_set('session.save_handler', $session_save_handler);
ini_set('session.save_path', $session_save_path);
ini_set('session.gc_probability', $session_gc_probability);
ini_set('session.gc_divisor', $session_gc_divisor);
// Check if custom sessions backend exists
$clsname = '\Zotlabs\Web\Session' . ucfirst(strtolower($session_save_handler));
if (class_exists($clsname)) {
$handler = new $clsname($session_save_path);
}
else {
ini_set('session.save_handler', $session_save_handler);
ini_set('session.save_path', $session_save_path);
ini_set('session.gc_probability', intval(get_config('system', 'session_gc_probability', 1)));
ini_set('session.gc_divisor', intval(get_config('system', 'session_gc_divisor', 100)));
}
}
}
else {
$handler = new \Zotlabs\Web\SessionHandler();
$handler = new SessionHandler();
}
if (isset($handler)) {
$this->handler = $handler;
$x = session_set_save_handler($handler,false);
if(! $x)
logger('Session save handler initialisation failed.',LOGGER_NORMAL,LOG_ERR);
$x = session_set_save_handler($handler, false);
if(! $x)
logger('Session save handler initialisation failed.',LOGGER_NORMAL,LOG_ERR);
}
// Force cookies to be secure (https only) if this site is SSL enabled.
// Must be done before session_start().

View File

@@ -0,0 +1,123 @@
<?php
namespace Zotlabs\Web;
class SessionRedis implements \SessionHandlerInterface {
private $redis = null;
function __construct($connection) {
$this->redis = new \Redis();
$credentials = parse_url($connection);
try {
if (isset($credentials['path']))
$this->redis->connect($credentials['path']);
else {
if (isset($credentials['query']))
parse_str($credentials['query'], $vars);
else
$vars = [];
$this->redis->connect(
(isset($credentials['scheme']) ? $credentials['scheme'] . '://' : '') . $credentials['host'],
(isset($credentials['port']) ? $credentials['port'] : 6379),
(isset($vars['timeout']) ? $vars['timeout'] : 1),
null,
0,
(isset($vars['read_timeout']) ? $vars['read_timeout'] : 0)
);
if (isset($vars['auth']))
$this->redis->auth($vars['auth']);
}
}
catch(\RedisException $ex) {
logger('Error connecting to Redis: ' . $ex->getMessage());
}
}
function open($s, $n) {
return true;
}
// IMPORTANT: if we read the session and it doesn't exist, create an empty record.
// We rely on this due to differing PHP implementation of session_regenerate_id()
// some which call read explicitly and some that do not. So we call it explicitly
// just after sid regeneration to force a record to exist.
function read($id) {
if ($id) {
$data = $this->redis->get($id);
if ($data)
return $data;
else
$this->redis->setEx($id, 300, '');
}
return '';
}
function write($id, $data) {
// Pretend everything is hunky-dory, even though it isn't.
// There probably isn't anything we can do about it in any event.
// See: https://stackoverflow.com/a/43636110
if(! $id || ! $data)
return true;
// Unless we authenticate somehow, only keep a session for 5 minutes
// The viewer can extend this by performing any web action using the
// original cookie, but this allows us to cleanup the hundreds or
// thousands of empty sessions left around from web crawlers which are
// assigned cookies on each page that they never use.
$expire = 300;
if($_SESSION) {
if(array_key_exists('remember_me',$_SESSION) && intval($_SESSION['remember_me']))
$expire = 60 * 60 * 24 * 365;
elseif(local_channel())
$expire = 60 * 60 * 24 * 3;
elseif(remote_channel())
$expire = 60 * 60 * 24 * 1;
}
$this->redis->setEx($id, $expire, $data);
return true;
}
function close() {
return true;
}
function destroy ($id) {
$this->redis->del($id);
return true;
}
function gc($expire) {
return true;
}
}

View File

@@ -12,10 +12,14 @@ class Activity_filter {
if(! local_channel())
return '';
$cmd = \App::$cmd;
$filter_active = false;
$tabs = [];
$filter_active = '';
$dm_active = '';
$events_active = '';
$polls_active = '';
$starred_active = '';
$conv_active = '';
$tabs = [];
$cmd = \App::$cmd;
if(x($_GET,'dm')) {
$dm_active = (($_GET['dm'] == 1) ? 'active' : '');
@@ -64,6 +68,8 @@ class Activity_filter {
);
if($groups) {
$group_active = '';
foreach($groups as $g) {
if(x($_GET,'gid')) {
$group_active = (($_GET['gid'] == $g['id']) ? 'active' : '');
@@ -95,6 +101,8 @@ class Activity_filter {
$channel = App::get_channel();
if($forums) {
$forum_active = '';
foreach($forums as $f) {
if(x($_GET,'pf') && x($_GET,'cid')) {
$forum_active = ((x($_GET,'pf') && $_GET['cid'] == $f['abook_id']) ? 'active' : '');
@@ -103,10 +111,10 @@ class Activity_filter {
$fsub[] = [
'label' => $f['xchan_name'],
'img' => $f['xchan_photo_s'],
'url' => (($f['private_forum']) ? $f['xchan_url'] . '/?f=&zid=' . $channel['xchan_addr'] : z_root() . '/' . $cmd . '/?f=&pf=1&cid=' . $f['abook_id']),
'url' => ((isset($f['private_forum'])) ? $f['xchan_url'] . '/?f=&zid=' . $channel['xchan_addr'] : z_root() . '/' . $cmd . '/?f=&pf=1&cid=' . $f['abook_id']),
'sel' => $forum_active,
'title' => t('Show posts to this forum'),
'lock' => (($f['private_forum']) ? 'lock' : '')
'lock' => ((isset($f['private_forum'])) ? 'lock' : '')
];
}
@@ -160,6 +168,8 @@ class Activity_filter {
);
if($terms) {
$file_active = '';
foreach($terms as $t) {
if(x($_GET,'file')) {
$file_active = (($_GET['file'] == $t['term']) ? 'active' : '');

View File

@@ -9,7 +9,7 @@ class Cover_photo {
require_once('include/channel.php');
$o = '';
if(\App::$module == 'channel' && $_REQUEST['mid'])
if(\App::$module == 'channel' && isset($_REQUEST['mid']))
return '';
$channel_id = 0;

View File

@@ -175,13 +175,13 @@ class Notifications {
];
}
$o = replace_macros(get_markup_template('notifications_widget.tpl'), array(
$o = replace_macros(get_markup_template('notifications_widget.tpl'), [
'$module' => \App::$module,
'$notifications' => $notifications,
'$no_notifications' => t('Sorry, you have got no notifications at the moment'),
'$loading' => t('Loading'),
'$startpage' => $channel['channel_startpage']
));
'$startpage' => ($channel ? $channel['channel_startpage'] : '')
]);
return $o;

View File

@@ -43,7 +43,7 @@ class Pinned {
$midb64 = 'b64.' . base64url_encode($item['mid']);
if(in_array($observer['xchan_hash'], get_pconfig($item['uid'], 'pinned_hide', $midb64, [])))
if(isset($observer['xchan_hash']) && in_array($observer['xchan_hash'], get_pconfig($item['uid'], 'pinned_hide', $midb64, [])))
continue;
$author = channelx_by_hash($item['author_xchan']);
@@ -67,7 +67,7 @@ class Pinned {
$conv_responses['attendno'] = [ 'title' => t('Not attending','title') ];
$conv_responses['attendmaybe'] = [ 'title' => t('Might attend','title') ];
if($commentable && $observer) {
$attend = array( t('I will attend'), t('I will not attend'), t('I might attend'));
$attend = [ t('I will attend'), t('I will not attend'), t('I might attend') ];
$isevent = true;
}
}
@@ -78,7 +78,7 @@ class Pinned {
$conv_responses['disagree'] = [ 'title' => t('Disagree','title') ];
$conv_responses['abstain'] = [ 'title' => t('Abstain','title') ];
if($commentable && $observer) {
$conlabels = array( t('I agree'), t('I disagree'), t('I abstain'));
$conlabels = [ t('I agree'), t('I disagree'), t('I abstain') ];
$canvote = true;
}
}
@@ -93,14 +93,13 @@ class Pinned {
// This actually turns out not to be possible in some protocol stacks without opening up hundreds of new issues.
// Will allow it only for uri resolvable sources.
if(strpos($item['mid'],'http') === 0) {
$share = []; //Not yet ready for primetime
//$share = array( t('Repeat This'), t('repeat'));
$share = []; // Isn't yet ready for primetime
//$share = [ t('Repeat This'), t('repeat') ];
}
$embed = array( t('Share This'), t('share'));
$embed = [ t('Share This'), t('share') ];
}
if(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0)
$is_new = true;
$is_new = boolval(strcmp(datetime_convert('UTC','UTC',$item['created']),datetime_convert('UTC','UTC','now - 12 hours')) > 0);
$body = prepare_body($item,true);
@@ -118,7 +117,7 @@ class Pinned {
'isevent' => $isevent,
'attend' => $attend,
'consensus' => $consensus,
'conlabels' => $conlabels,
'conlabels' => ($canvote ? $conlabels : []),
'canvote' => $canvote,
'linktitle' => sprintf( t('View %s\'s profile - %s'), $profile_name, ($author['xchan_addr'] ? $author['xchan_addr'] : $author['xchan_url']) ),
'olinktitle' => sprintf( t('View %s\'s profile - %s'), $owner['xchan_name'], ($owner['xchan_addr'] ? $owner['xchan_addr'] : $owner['xchan_url']) ),
@@ -135,7 +134,6 @@ class Pinned {
'localtime' => datetime_convert('UTC', date_default_timezone_get(), $item['created'], 'r'),
'editedtime' => (($item['edited'] != $item['created']) ? sprintf( t('last edited: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['edited'], 'r') ) : ''),
'expiretime' => ($item['expires'] > NULL_DATE ? sprintf( t('Expires: %s'), datetime_convert('UTC', date_default_timezone_get(), $item['expires'], 'r') ) : ''),
'lock' => $lock,
'verified' => $verified,
'forged' => $forged,
'location' => $location,
@@ -150,12 +148,12 @@ class Pinned {
'event' => $body['event'],
'has_tags' => (($body['tags'] || $body['categories'] || $body['mentions'] || $body['attachments'] || $body['folders']) ? true : false),
// Item toolbar buttons
'share' => $share,
'embed' => $embed,
'share' => (isset($share) && count($share) ? $share : false),
'embed' => (isset($embed) && count($embed) ? $embed : false),
'plink' => get_plink($item),
'pinned' => t('Pinned post'),
'pinme' => (($observer['xchan_hash'] == $owner['xchan_hash']) ? t('Unpin from the top') : ''),
'hide' => (! $is_new && $observer && ($observer['xchan_hash'] != $owner['xchan_hash']) ? t("Don't show") : ''),
'pinme' => (isset($observer['xchan_hash']) && $observer['xchan_hash'] == $owner['xchan_hash'] ? t('Unpin from the top') : ''),
'hide' => (! $is_new && isset($observer['xchan_hash']) && $observer['xchan_hash'] != $owner['xchan_hash'] ? t("Don't show") : ''),
// end toolbar buttons
'modal_dismiss' => t('Close'),
'responses' => $conv_responses

View File

@@ -52,10 +52,10 @@ require_once('include/attach.php');
require_once('include/bbcode.php');
define ( 'PLATFORM_NAME', 'hubzilla' );
define ( 'STD_VERSION', '5.4.2' );
define ( 'STD_VERSION', '5.6' );
define ( 'ZOT_REVISION', '6.0' );
define ( 'DB_UPDATE_VERSION', 1243 );
define ( 'DB_UPDATE_VERSION', 1245 );
define ( 'PROJECT_BASE', __DIR__ );
@@ -2316,13 +2316,14 @@ function construct_page() {
$navbar = get_pconfig($uid,'system','navbar',$navbar);
}
if($comanche && App::$layout['navbar']) {
if($comanche && isset(App::$layout['navbar'])) {
$navbar = App::$layout['navbar'];
}
if (App::$module == 'setup') {
$installing = true;
} else {
}
else {
nav($navbar);
}
@@ -2428,7 +2429,6 @@ function construct_page() {
'style-src' => [ "'self'", "'unsafe-inline'" ],
'frame-src' => [ "'self'" ]
];
call_hooks('content_security_policy',$cspsettings);
// Legitimate CSP directives (cxref: https://content-security-policy.com/)
@@ -2460,6 +2460,14 @@ function construct_page() {
header("X-Content-Type-Options: nosniff");
}
if (isset(App::$config['system']['perm_policy_header']) && App::$config['system']['perm_policy_header']) {
header("Permissions-Policy: " . App::$config['system']['perm_policy_header']);
}
else {
// opt-out this site from federated browser surveillance
header("Permissions-Policy: interest-cohort=()");
}
if(isset(App::$config['system']['public_key_pins'])) {
header("Public-Key-Pins: " . App::$config['system']['public_key_pins']);
}

112
doc/admin/zarlog_msgs.md Normal file
View File

@@ -0,0 +1,112 @@
~~~
L regate ZAR1131E dId2 mistaken
L ZAR1132E Identity unknown
ZAR1133A Sorry for any inconvience. Thank you for your response.
L ZAR1134S email verfication denied {did2}
L ZAR1135E not awaited url parameter received
L regate ZAR1230S Unexpected registration verification request for
L ZAR1231E dId2 mistaken
L ZAR1232E Identity unknown
L ZAR1234W Request not inside time frame
L ZAR1235E Token verification failed
ZAR1236I Verify successfull
L ZAR1236E Verify failed
L ZAR1237D unexpected
(reason may be caused by new account flags implemented still not known)
ZAR1238I Email resent
ZAR1238E Resent failed
L ZAR1239I Account successfull created
L ZAR1239E Account creation error
register ZAR0130E Registration on this hub is disabled.
ZAR0131I Registration on this hub is by approval only.
Register at another affiliated hub in case when prefered
ZAR0132I Registration on this hub is by invitation only.
Register at another affiliated hub
ZAR0133I If the registation was already submitted with your data once ago,
enter your identity (like email) here and submit
ZAR0134I I have an invite code
ZAR0135I This site requires verification. After completing this form,
please check the notice or your email for further instructions.
ZAR0136I Your email address (or leave blank to register without email)
L register ZAR0230S Unexpected registration request
ZAR0231E Email address mistake
ZAR0231E Passwords do not match.
ZAR0231E Please indicate acceptance of the Terms of Service. Registration failed.
ZAR0232E Invitations are not available
L ZAR0233E Registration on this hub is by invitation only
L ZAR0234S Invitation code failed
L ZAR0235S Invitation email failed
ZAR0236E Invitation not in time or too late
ZAR0237I Invitation code succesfully applied
L ZAR0238E Email address already in use
L ZAR0239D Error creating dId A
ZAR0239I Your didital id is {did2} and your pin for is {pin}
Keep these infos and your entered password safe
Valid from ... nd expire ...
L ZAR0239S Exceeding same ip register request of
ui:admin:site
ZAR0810C Register text
Will be displayed prominently on the registration page.
ZAR0820C register_policy
Does this site allow new member registration?
ZAR0830C Registration office on duty
The weekdays and hours the register office is open for registrations
ZAR0831I Testmode duties
(interactive)
ZAR0840C Account registrations max per day
How many registration requests the site accepts during one day. Unlimited if zero or no value.
ZAR0850C Account registrations from same ip
How many pending registration requests the site accepts from a same ip address.
ZAR0860C Account registration delay
How long a registration request has to wait before validation can perform
ZAR0862C Account registration expiration
How long a registration to confirm remains valid. Not expire if zero or no value
ZAR0870C Auto channel create
Auto create a channel when register a new account. When On, the register form will show
additional fields for the channel-name and the nickname.
ZAR0880C Invitation only
Only allow new member registrations with an invitation code.
Above register policy must be set to Yes.
ZAR0881C Invitation also
Also allow new member registrations with an invitation code.
Above register policy must be set to Yes.
ZAR0890C Verify Email Addresses
Check to verify email addresses used in account registration (recommended).
invite ZAI0100E All users invitation limit exceeded
ZAI0101E Permission denied.
ZAI0102E Invite App (Not Installed)
ZAI0103E Invites not proposed by configuration. Contact the site admin
ZAI0104E Invites by users not enabled
ZAI0105W You have no more invitations available
ZAI0106I Invitations I am using
ZAI0107I Invitations we are using
ZAI0109E Not on xchan
ZAI0110I § Note, the email(s) sent will be recorded in the system logs
(see ZAI0208I @ L)
ZAI0111I Enter email addresses, one per line
ZAI0112I Your message
Here you may enter personal notes to the recipient(s)
ZAI0113I Invite template
ZAI0114I Note, the invitation code is valid up to ...
invite ZAI0201E Permission denied.
ZAI0202E Invite App (Not Installed)
ZAI0203E Not a valid email address
ZAI0204E Not a real email address
ZAI0205E Not allowed email address
ZAI0206E mail address already in use
ZAI0207I Note, the invitation code is valid up to
ZAI0208E Message delivery failed.
ZAI0208I Message delivery success.
L ZAI0208I to {email} Message delivery success. ({account#}, {channel#}, from:{email}})
ZAI0209I Accepted email address
ZAI0210E Too many recipients for one invitation (max n)
ZAI0211E No recipients for this invitation
ZAI0212I n mail(s) sent, n mail error(s)
ZAI0213E Register is closed
~~~

View File

@@ -0,0 +1,12 @@
<dl class="dl-horizontal">
<dt>Allgemein</dt>
<dd>Auf dieser Seite können sich Besucher registrieren, um mit einer Anmeldungskennung Zugang zum Portal zu erhalten. Angemeldeten Benutzern sehen nicht nur die öffentlichen Inhalte, sondern können selber Inhalte veröffentlichen und Soziale Netzwerk Kommunikationen durchführen, und sehr viel mehr.</dd>
<dt>Arten der Registrierung</dt>
<dd>Eine Registrierung ist mit einer eMail Adresse möglich, oder auch anonym (dann das eMail Feld nicht ausfüllen). Vielleicht haben Sie auch einen Einladungscode erhalten, der dann mit der eMail Adresse angegeben werden kann. Der Link oberhalb des Feldes eMail ermöglich die Eingabe des Einladungscodes.</dd>
<dt>Ablauf der Registrierung</dt>
<dd>Für Anmeldungen nach einer erfolgreichen Registrierung ist ein eigenes Kennwort festzulegen. Es ist sicherheitshalber zweimal mit identischen Werten einzugeben, weil es nicht angezeigt wird. Das Kennwort ist geheim zu halten und nur für den eigenen Gebrauch bestimmt. Anonym registrierte Benutzer erhalten eine automatisch zugewiesene Kennung, und sollten das eigene Kennwort nicht vergessen, weil es im Gegensatz zur eMail Registrierung zunächst keine Rücksetzfunktion gibt. Je nach Konfiguration der Hub-Instanz kann eine Bestätigungsfunktion erforderlich sein. Benutzer der eMail Registrierung erhalten eine entsprechende Nachricht. Bei anonymen Registrierungen wird ein weiterer Dialog angezeigt, der die Zugangskennung und eine Pin zeigt. Jene Dialogseite sollte unbedingt sicher und langfristig aufbewahrt werden (z.B. durch Ausdruck, Screenshot, Foto), weil die Daten zu einem späten Zeitpunkt noch einmal zu bestätigen sind.</dd>
<dt>Die Digitale Identität</dt>
<dd>Je nach Konfiguration der Hub-Instanz kann bereits bei der Registrierung (alternativ auch bei der ersten Anmeldung) ein anzeigbarer Name und ein Spitzname ("nickname") eingegeben werden. Der Nickname hat eine sehr weitreichende Bedeutung und läßt sich nachträglich nicht mehr ändern. Es handelt sich dabei um eine eindeutige Digitale Identität (DID), die mit allen eigenen Aktivitäten verknüft ist, sein wird, und bleibt. Diese DID eignet sich nicht nur zur Anmeldung in dieser Hub-Instanz, sondern auch in allen verbundenen Instanzen des Federalen Netzwerkes. Im Sprachgebrauch der Federalen Netze ist diese digitale Identität ein "Kanal". Das ist vergleichbar etwa mit einer Rufnummer im Telefonnetz. Die DID hat das Format kanal@instanz.tld = nickname@instanz.tld und ist, wie gesagt, nachträglich nicht mehr änderbar. Obwohl sich das Format wie eine eMail Adresse darstellt, handelt es sich nicht um eine solche.</dd>
<dt>Bevor die Registrierung begonnen wird ...</dt>
<dd>sollte (oben rechts im Hamburger Menü <span class="fa fa-fw fa-bars"> </span>) die bevorzugte Sprache (Englisch, Spanisch, Deutsch z.B.) gewählt werden. Die aktuelle Sprache wird in den Folgeschritten und auch bei und nach der Anmeldung verwendet. Das läßt sich aber jederzeit und je nach Bedarf ändern. Auch sei darauf hingewiesen, dass diese Hub-Instanz nicht die einzige ist. Eine Übersicht über andere Hub-Instanzen ist <a href="./pubsites"> hier </a> zu finden.</dd>
</dl>

View File

@@ -0,0 +1,12 @@
<dl class="dl-horizontal">
<dt>General</dt>
<dd>On this page visitors can register to get access to the portal with a login ID. Logged in users not only see the public content, but can publish content themselves and perform social network communications, and much more.</dd>
<dt>Modes of registration</dt>
<dd>Registration is possible with an eMail address, or anonymously (then do not fill in the eMail field). You may also have received an invitation code, which can then be entered with the eMail address. The link above the eMail field allows you to enter the invitation code.</dd>
<dt>Registration procedure</dt>
<dd>For logins after a successful registration, a separate password must be set. To be on the safe side, enter it twice with identical values, because it will not be displayed. The password is to be kept secret and is only intended for the user's own use. Anonymously registered users receive an automatically assigned ID, and should not forget their own password because, unlike eMail registration, there is initially no reset function. Depending on the configuration of the hub instance, a confirmation function may be required. Users of the eMail registration will receive a corresponding message. For anonymous registrations, another dialog will be displayed showing the access ID and a pin. This dialog page should be stored securely and for a long time (e.g. by printout, screenshot, photo), because the data must be confirmed again at a later point in time.</dd>
<dt>The Digital Identity</dt>
<dd>Depending on the configuration of the hub instance, a displayable name and a nickname can already be entered during registration (alternatively also during the first login). The nickname has a very extensive meaning and cannot be changed later. It is a unique Digital Identity (DID) that is, will be, and remains linked to all of one's activities. This DID is not only suitable for logging into this hub instance, but also into all connected instances of the federal network. In federal network parlance, this digital identity is a "channel". This is comparable to a telephone number in the telephone network. The DID has the format channel@instance.tld = nickname@instance.tld and, as mentioned, cannot be changed afterwards. Although the format looks like an eMail address, it is not.</dd>
<dt>Before starting the registration ...</dt>
<dd>... the preferred language (English, Spanish, German, for example) should be selected (top right in the hamburger menu <span class="fa fa-fw fa-bars"> </span>). The current language is used in the subsequent steps and also during and after login. However, this can be changed at any time and as needed. It should also be noted that this Hub instance is not the only one. An overview of other Hub instances can be found <a href="./pubsites"> here </a>.</dd>
</dl>

View File

@@ -2,6 +2,6 @@
<dt>Ogólne</dt>
<dd>
Statystyki kolejki pokazują, ile postów znajduje się w kolejce do dostarczenia
do innych hubów. Priorytet jest powiązany z liczbą nieudanych prób dostawy.
do innych węzłów. Priorytet jest powiązany z liczbą nieudanych prób dostawy.
</dd>
</dl>

View File

@@ -22,8 +22,8 @@
<li>
<b>Kategorie</b>: Jeśli na swoim kanale masz włączoną
<a href="/settings/features"> funkcjonalność kategorii postów </a>,
możesz dodawać kategorie do karty. Te kategorie zapełniają listę
<b>Kategorie</b> na lewym panelu i umożliwiają filtrowanie
możesz dodawać kategorie do karty. Kategorie te zawarte są na liście
<b>Kategorie</b>, na lewym panelu i umożliwiają filtrowanie
kolekcji kart.
</li>
</ul>

View File

@@ -14,6 +14,6 @@
<dd>
Wpisz wiadomość w polu wiadomości i naciśnij "Prześlij". Możesz ustawić status,
wybierając przycisk menu pokoju rozmów sieciowych obok przycisku "Wyślij".
Inne osoby "w pokoju"" są widoczne w panelu bocznym w panelu Członkowie czatu.
Inne osoby "w pokoju" są widoczne w panelu bocznym w panelu "Członkowie czatu".
</dd>
</dl>

View File

@@ -1,7 +1,7 @@
<dl class="dl-horizontal">
<dt>Ogólne</dt>
<dd>
Ta strona wyświetla pliki "w chmurze" kanału. To co widi przeglądajacy zależy
Ta strona wyświetla pliki "w chmurze" kanału. To co widzi przeglądajacy zależy
od jego indywidualnych uprawnień do plików, które ustawia właściciel kanału.
Jeśli masz uprawnienia do tworzenia i przesyłania plików, zobaczysz przyciski
kontrolne nad listą plików.

View File

@@ -22,7 +22,7 @@
title="Kliknij, aby podświetlić element...">Grupy prywatności</a></dt>
<dd>
Każde połączenie może być przypisane do jednej lub więcej grup prywatności
w celu grupowania kolekcji znajomych z dostępem do określonych postów,
w celu grupowania kolekcji znajomych z dostępem do określonych wpisów,
multimediów i innych treści. Możesz dodać je tutaj do istniejącej grupy
prywatności lub utworzyć nową grupę prywatności. Po dodaniu ich do istniejącej
grupy akcja jest natychmiastowa i nie musisz przesyłać formularza.
@@ -37,7 +37,7 @@
<dt>Ustawienia specyficznych funkcji</dt>
<dd>
Szereg indywidualnych ustawień jest kontrolowanych za pomocą dodatkowych
funkcji, które mogą, ale nie muszą być aktywowane na Twoim hubie lub na Twoim
funkcji, które mogą, ale nie muszą być aktywowane na Twoim węźle lub na Twoim
kanale. Kilka opcjonalnych funkcji ma ustawienia dla każdego połączenia,
które można ustawić na tej stronie za pomocą dodatkowych zakładek formularza.
</dd>

View File

@@ -6,7 +6,7 @@
</dd>
<dt>Widok łączony</dt>
<dd>
Wybór opcji <b>Widok łączony</b> spowoduje wyświetlanie całych rozmów w ciągłym
Wybór opcji <b>Widok łączony</b> spowoduje wyświetlanie wszystkich rozmów w ciągłym
wątku. Dostępne rozmowy są wyświetlane poniżej menu w panelu bocznym.
</dd>
<dt>Skrzynka odbiorcza/nadawcza</dt>

View File

@@ -1,33 +1,33 @@
<dl class="dl-horizontal">
<dt>Ogólne</dt>
<dd>
Strona strumienia sieciowego wyświetla strumień postów i rozmów, zwykle
Strona strumienia sieciowego wyświetla strumień wpisów i rozmów, zwykle
uporządkowanych według ostatnio zaktualizowanych. Jest to strona wysoce konfigurowalna.
</dd>
<dt><a href='#' onclick='contextualHelpFocus("#profile-jot-wrapper", 0);
return false;' title="Kliknij, aby podświetlić element...">Tworzenie posta</a></dt>
return false;' title="Kliknij, aby podświetlić element...">Tworzenie wpisu</a></dt>
<dd>
U góry strony znajduje się pole tekstowe z napisem "Udostępnij". Kliknięcie
tego pola otwiera nowy edytor postówów. Edytor postów można dostosowywać, ale
podstawowy edytor udostępnia pola dla treści posta i opcjonalnego <b>tytułu</b>.
tego pola otwiera nowy edytor wpisów. Edytor wpisów można dostosowywać, ale
podstawowy edytor udostępnia pola dla treści wpisu i opcjonalnego <b>tytułu</b>.
Przyciski poniżej obszaru tekstowego po lewej stronie zapewniają skróty do
formatowania tekstu i wstawiania linków, obrazów i innych danych do posta.
Przyciski po prawej stronie zapewniają podgląd posta, ustawienia uprawnień do
publikowania oraz przycisk <b>Prześlij</b> do wysłania posta.
formatowania tekstu i wstawiania linków, obrazów i innych danych do wpisu.
Przyciski po prawej stronie zapewniają podgląd wpisu, ustawienia uprawnień do
publikowania oraz przycisk <b>Prześlij</b> do wysłania wpisu.
</dd>
<dt><a href='#' onclick='contextualHelpFocus("#group-sidebar", 1);
return false;' title="Kliknij, aby podświetlić element...">Grupy prywatności</a></dt>
<dd>
Utworzone grupy prywatności są wyświetlane w panelu bocznym. Wybranie ich
powoduje filtrowanie postów do tych utworzonych przez kanały w wybranej grupie.
powoduje filtrowanie wpisów do tych utworzonych przez kanały w wybranej grupie.
</dd>
<dt><a href='#' onclick='$("#dbtn-acl").click(); return false;'
title="Kliknij, aby podświetlić element...">Uprawnienia do posta</a></dt>
title="Kliknij, aby podświetlić element...">Uprawnienia do wpisu</a></dt>
<dd>
Lista kontroli dostępu (ACL) służy do określania, kto może zobaczyć Twój nowy
post. Naciśnięcie przycisku ACL obok przycisku Prześlij spowoduje wyświetlenie
wpis. Naciśnięcie przycisku ACL obok przycisku Prześlij spowoduje wyświetlenie
okna dialogowego, w którym możesz wybrać kanały albo grupy prywatności, które
będą widzieć post. Możesz także wybrać, komu wyraźnie odmówiono dostęp.
będą widzieć wpis. Możesz także wybrać, komu wyraźnie odmówiono dostęp.
Załóżmy na przykład, że planujesz przyjęcie niespodziankę dla znajomego.
Możesz wysłać zaproszenie do wszystkich w swojej grupie <b>Znajomi</b>
<i>oprócz</i> znajomego, którego zaskakujesz. W tym przypadku "pokazujesz"

View File

@@ -35,7 +35,7 @@
się z osobami w życiu codziennym. Lecz być może jesteś zapalonym
czytelnikiem książek a wielu ludzi się tym nudzi. Otwierasz więc
<i>drugi kanał</i> dla miłośników książek, gdzie wszyscy mogą rozmawiać
o książkach tyle, ile zechcą. Oczywiście jest to nowy strumień postów,
o książkach tyle, ile zechcą. Oczywiście jest to nowy strumień wpisów,
z nowym profilem (... lub nowymi profilami) i zupełnie z innymi
kontaktami. Niektóre połączenia mogą istnieć w obu kanałach, ale będą
takie, które będą występować wyłącznie w jednym z nich. Ty po prostu

View File

@@ -35,7 +35,7 @@
się z osobami w życiu codziennym. Lecz być może jesteś zapalonym
czytelnikiem książek a wielu ludzi się tym nudzi. Otwierasz więc
<i>drugi kanał</i> dla miłośników książek, gdzie wszyscy mogą rozmawiać
o książkach tyle, ile zechcą. Oczywiście jest to nowy strumień postów,
o książkach tyle, ile zechcą. Oczywiście jest to nowy strumień wpisów,
z nowym profilem (... lub nowymi profilami) i zupełnie z innymi
kontaktami. Niektóre połączenia mogą istnieć w obu kanałach, ale będą
takie, które będą występować wyłącznie w jednym z nich. Ty po prostu

View File

@@ -35,7 +35,7 @@
się z osobami w życiu codziennym. Lecz być może jesteś zapalonym
czytelnikiem książek a wielu ludzi się tym nudzi. Otwierasz więc
<i>drugi kanał</i> dla miłośników książek, gdzie wszyscy mogą rozmawiać
o książkach tyle, ile zechcą. Oczywiście jest to nowy strumień postów,
o książkach tyle, ile zechcą. Oczywiście jest to nowy strumień wpisów,
z nowym profilem (... lub nowymi profilami) i zupełnie z innymi
kontaktami. Niektóre połączenia mogą istnieć w obu kanałach, ale będą
takie, które będą występować wyłącznie w jednym z nich. Ty po prostu

View File

@@ -1,35 +1,50 @@
<dl class="dl-horizontal">
<dt>Ogólne</dt>
<dt>Informacje ogólne</dt>
<dd>
Ta strona umożliwia skonfigurowanie ustawień dla wielu dodatkowych funkcji Hubzilli.
Ta strona umożliwia skonfigurowanie ustawień dla wielu dodatkowych funkcji Hubzilli, które możesz włączyć na swoim koncie.
</dd>
<dt><a href='#' onclick='$("#general-settings-title h3 a").click();
setTimeout((function() {contextualHelpFocus("#general-settings-title", 0)}), 1000);
return false;' title="Klikniaj, aby podświetlić element...">Główne cechy</a></dt>
<dt><a href="/help/pl/feature/additional/overview#calendar_settings">Kalendarz</a></dt>
<dd>
Ogólne ustawienia funkcji zawierają opcje związane z Twoim kanałem, takie jak
hosting strony internetowej i wiki.
Są to dodatkowe opcje, które możesz włączyć dla wszystkich swoich kalendarzy.
Można to zmienić indywidualnie w każdym kalendarzu.<br />
</dd>
<dt><a href='#' onclick='$("#composition-settings-title h3 a").click();
setTimeout((function() {contextualHelpFocus("#composition-settings-title", 0)}), 1000);
return false;' title="Klikniaj, aby podświetlić element...">Funkcje kompozycji postów</a></dt>
<dt><a href="/help/pl/feature/additional/overview#channel_main_page_settings">Strona główna kanału</a></dt>
<dd>
Funkcje kompozycji postów zapewniają dodatkowe opcje i możliwości podczas
tworzenia nowych postów.
Kilka dodatkowych możliwości związanych ze stroną główną kanału.
</dd>
<dt><a href='#' onclick='$("#net_module-settings-title h3 a").click();
setTimeout((function() {contextualHelpFocus("#net_module-settings-title", 0)}), 1000);
return false;' title="Klikniaj, aby podświetlić element...">Sieć i fitrowanie strumienia</a></dt>
<dt><a href="/help/pl/feature/additional/overview#connections_settings">Połączenia</a></dt>
<dd>
Te ustawienia modyfikują funkcje związane z filtrowaniem i kontrolowaniem widoku
przychodzących postów.
Obecnie jest tu tylko ustawienie opcji umożliwiającej filtrowanie strumienia wg
słów kluczowych lub treści (fraz).
</dd>
<dt><a href='#' onclick='$("#tools-settings-title h3 a").click();
setTimeout((function() {contextualHelpFocus("#tools-settings-title", 0)}), 1000);
return false;' title="Klikniaj, aby podświetlić element...">Narzędzia postów i komentarzy</a></dt>
<dt><a href="/help/pl/feature/additional/overview#conversation-settings">Rozmowa</a></dt>
<dd>
Ustawienia te zapewniają dodatkowe narzędzia do kategoryzowania postów
i umożliwiają dodatkowe metody komentowania, takie jak emoji lub tagowanie
społecznościowe.
Kilka dodatkowych opcji rozszerzających obsługę rozmów i dyskusji.
</dd>
<dt><a href="/help/pl/feature/additional/overview#directoty_settings">Katalog</a></dt>
<dd>
Dostępna tu opcja zaawansowanego przeszukiawania katalogu może być bardzo użyteczna
dla osób chcących dotrzeć do konkretnych informacji publikowanych w sieci Hubzilla.
</dd>
<dt><a href="/help/pl/feature/additional/overview#manage_settings">Zarządzanie</a></dt>
<dd>
Dostępna tu opcja włącza funkcję zmiany kanału bezpośrednio z rozwijanego menu nawigacji.
</dd>
<dt><a href="/help/pl/feature/additional/overview#network-settings">Sieć</a></dt>
<dd>
Znajduje się tu szereg opcji włączających funkcje związane z siecią i strumieniem
sieciowym. Przede wszystkim dostępnych jest tu kilka dodatkowych filtrów i inne
użyteczne funkcje. Szczegóły można znaleźć dokumentacji.
</dd>
<dt><a href="/help/pl/feature/additional/overview#photos_settings">Zdjęcia</a></dt>
<dd>
Tutaj można włączyć funkcję wyświetlania na mapie lokalizacji zdjęcia, jeśli
polik zdjęcia zawiera potrzebne metadane.
</dd>
<dt><a href="/help/pl/feature/additional/overview#profiles_settings">Profile</a></dt>
<dd>
W tej sekcji zawarte są opcje włączające dodatkowe funkcje dotyczące profilu.
Jeśli chcesz i możesz zakładać na swoim koncie wiele profili (i tożsamości),
włącz tu opcję "wiele profili".
</dd>
</dl>

View File

@@ -1,14 +1,14 @@
<dl class="dl-horizontal">
<dt><a href="/help/member/member_guide#Guest_Access_Tokens">Tokeny dostępu gościa</a></dt>
<dt><a href="/help/member/member_guide#Tokeny_dost_pu_go_cia">Tokeny dostępu gościa</a></dt>
<dd>
Aby ułatwić udostępnianie prywatnych zasobów osobom niebędącym członkami
lub członkami sfederyzowanych węzłów (hubów) i zapewnić zabezpieczone
lub członkami sfederyzowanych węzłów (węzłów) i zapewnić zabezpieczone
wykrywaniem danych identyfikacyjnych, Hubzilla zawiera mechanizm tworzenia
i zarządzania tymczasowymi ("jednorazowymi") loginami, zwanymi "tokenami
dostępu Zot”. Tokeny te, będące swojego rodzaju danymi uwierzytelniającymi,
mogą być używane do uwierzytelniania w serwisie Hubzilla wyłącznie w celu
uzyskania dostępu do uprzywilejowanych lub kontrolowanych zasobów (pliki,
zdjęcia, posty, strony internetowe, pokoje rozmów itp.).
zdjęcia, wpisy, strony internetowe, pokoje rozmów itp.).
</dd>
<dt>Utworzenie tokenu</dt>
<dd>

View File

@@ -1,2 +1,2 @@
Return to the [zrl=[baseurl]/help/addons]Dokumentacja dodatków[/zrl]
Return to the [zrl=[baseurl]/help/main]Główna dokumentacja[/zrl]
Powróć do [zrl=[baseurl]/help/addons]dokumentacji dodatków[/zrl]
Powróć do [zrl=[baseurl]/help/main]głównej strony dokumentacji[/zrl]

View File

@@ -1,2 +1,2 @@
Return to the [zrl=[baseurl]/help/cloud]Dokumentacja chmury[/zrl]
Return to the [zrl=[baseurl]/help/main]Główna strona dokumentacji[/zrl]
Powróć do [zrl=[baseurl]/help/cloud]dokumentacji chmury[/zrl]
Powróć do [zrl=[baseurl]/help/main]głównej strony dokumentacji[/zrl]

View File

@@ -1,107 +1,173 @@
Dodatkowe możliwości
Opcje konfiguracyjne
====================
Domyślny interfejs $Projectname został zaprojektowany tak, aby był dobrze uporządkowany. Istnieje ogromna liczba dodatkowych funkcji (niektóre są bardzo przydatne), które można włączyć i jak najlepiej wykorzystać. Można je znaleźć pod klikając link [Dodatkowe funkcje](settings/features) na stronie [Ustawienia](settings).
Po zainstalowaniu, serwis $Projectname jest wstępnie konfigurowany z domyślnymi wartościami. Z reguły, wymaga to odpowiedniego dostrojemia tak, aby konfiguracja odpowiadała zakładanym funkcjom serwisu.
**Wygaśnięcie treści**
Ustawianie dodatkowych możliwości poprzez interfejs graficzny
-------------------------------------------------------------
Usuwanie postów, komentarzy albo prywatnych wiadomości w określonym terminie. Do edytora postów zostaje dodany dodatkowy przycisk, za pomoca któreg można ustawić termin wygaśnięcia publikacji. Zwykle data jest wyświetlana w formacie „rrrr-mm-dd gg: mm”, ale w języku angielskim ma się nieco większą swobodę i można używać większości rozpoznawalnych odniesień do dat, takich jak "next Thursday" czy "+1 day". W określonym terminie (podanym lub zajmującym około dziesięciu minut, w zależności od częstotliwości sprawdzania zdalnego systemu) element jest usuwany.
Domyślny interfejs $Projectname został zaprojektowany tak, aby był dobrze uporządkowany. Istnieje spora liczba dodatkowych funkcjonalności (o różnej przydatności), które można włączyć i później wykorzystywać. Można je znaleźć klikając link [Dodatkowe możliwości](admin/features) na stronie [Administracja](/admin). Są one tam prezentowane w kilku grupach.
#### Kalendarz
**Rozpocznij tydzień kalendarzowy w poniedziałek**
Daje możliwość skonfigurowania kalendarza tak, aby tydzień kalendarzowy zaczynał się w poniedziałek.
**Wybór strefy czasowej wydarzenia**
Daje możliwość konfigurowania strefy czasowej wydarzenia w kalendarzu.
#### Strona główna kanału
**Wyszukaj po dacie**
Daje możliwość wyboru wpisów według zakresów dat.
**Chmura tagów**
Udostępnienie osobistej chmury tagów na stronie swojego kanału.
**Użyj trybu blog/lista**
Pozwoduje, że komentarze są wyświetlane osobno.
#### Połączenia
**Filtrowanie połączeń**
Umożliwia filtrowanie przychodzących wpisów z połączeń, na podstawie słów kluczowych lub fragnentów treści.
#### Rozmowa
**Reakcje emoji**
Dodaje możliwość wstawiania reakcji emoji we wpisach.
**Nielubienie wpisu**
Możliwość oznaczania wpisów i komentarzy jako nielubiane.
**Wyróżnienie wpisu**
Możliwość oznaczania wyróżnionych wpisów wskaźnikiem gwiazdki.
**Odpowiadanie na komentarze**
Możliwość udzielenia odpowiedzi na wybrany komentarz.
#### Katalog
**Zaawansowane przeszukiwanie katalogu**
Umożliwia tworzenie złożonych zapytań wyszukiwania w katalogu.
#### Edytor
**Kategorie wpisów**
Możliwość dodawania kategorii do swoich wpisów.
**Duże zdjęcia**
Możliwość zamieszczania dużych miniatur zdjęć (1024px) we wpisach. Jeśli nie jest to włączone, można używać tylko małych miniatur (640 px).
**Jeszcze więcej szyfrowania**
Zezwala na opcjonalne pełne (e2ee) szyfrowanie treści za pomocą wspólnego tajnego klucza.
Stadardowo, prywatne wiadomości są szyfrowane podczas transportu i przechowywania. W dzisiejszych czasach to szyfrowanie może nie wystarczyć, jeśli twoja komunikacja jest wyjątkowo wrażliwa. Ta opcja umożliwia dodatkowo szyfrowanie treści "end-toend" za pomocą wspólnego tajnego klucza. Sposób, w jaki odbiorca pozna tajny klucz, zależy wyłącznie od Ciebie. Możesz podać wskazówkę, na przykład "imię pierwszego psa cioci Kloci".
**Wyłączenie komentarzy**
Zapewnia możliwość wyłączenia komentowania wpisu
**Opóźnione publikowanie**
Pozwala na publikację wpisów w późniejszym terminie
**Wygasanie treści**
Usuwanie wpisów, komentarzy albo prywatnych wiadomości w określonym terminie. Do edytora wpisów zostaje dodany dodatkowy przycisk, za pomoca któreg można ustawić termin wygaśnięcia publikacji. Zwykle data jest wyświetlana w formacie „rrrr-mm-dd gg: mm”, ale w języku angielskim ma się nieco większą swobodę i można używać większości rozpoznawalnych odniesień do dat, takich jak "next Thursday" czy "+1 day". W określonym terminie (podanym lub zajmującym około dziesięciu minut, w zależności od częstotliwości sprawdzania zdalnego systemu) element jest usuwany.
**Pomijaj zduplikowane wpisy i komentarze**
Zapobiegaj publikowaniu wpisów o identycznej treści, mających mniej niż dwie minuty między przesłaniami.
**Automatyczne zapisywanie roboczych wpisów i komentarzy**
Automatycznie zapisuje wersje robocze wpisów i komentarzy w lokalnej pamięci przeglądarki, aby zapobiec przypadkowej utracie kompozycji.
#### Zarządzanie
**Wybór kanału poprzez nawigację**
Zmiana kanału bezpośrednio z rozwijanego menu nawigacji.
#### Sieć
**Filtr wydarzeń**
Możliwość wyświetlania tylko wydarzeń.
**Filtr ankiet**
Możliwość wyświetlania tylko ankiet.
**Zapisywane wyszukiwanie**
Możliwość zapisywania wyszukiwanych haseł do ponownego wykorzystania.
**Zapisywane foldery**
Możliwość umieszczania wpisów w folderach
**Alternatywan kolejność strumienia**
Możliwość uporządkowania strumienia według daty ostatniego wpisu, daty ostatniego komentarza lub nieprzeczytanych aktywności.
**Filtr kontaktów**
Możliwość wyświetlania wpisów autorstwa tylko wybranego kontaktu.
**Filtr forów**
Możliwość wyświetlania wpisów tylko z określonego forum.
**Filtr wpisów osobistych**
Filtr wpisów osobistych.
**Użyj trybu blog/lista**
Pozwoduje, że komentarze są wyświetlane osobno.
#### Zdjęcia
**Lokalizowanie zdjęć**
Jeśli dane lokalizacji są dostępne na przesłanych zdjęciach, połącz je z mapą.
##### Profile
**Profile zaawansowane**
Dodatkowe sekcje i pola wyboru profilu. Rozszerza to zakres informacji profilowych zbieranych w serwisie. Włączenie tej funkcjonalności powinno znaleźć odzwierciedlenie w dokumencie "Polityka prywatności", w której należy wymienić wszystkie rodzaje informacji osobistych zbieranych i utrzymywanych w serwisie. W większości przypadków jest to funkcjonalność nieprzydatna i nie powinno się jej włączać.
**Import/Eksport proflilu**
Możliwość zaimportowania lub wyeksportowania swojego profilu na inne serwisy (węzły sieci Zot). Funkcjonalność ta związana jest z nomadycznością tożsamości internetowej w $Projectname. Domyślnie Twoja tożsamość "podróżuje" z Tobą, gdy przeglądasz matrycę zdalnych witryn - tam też wiedzą kim jesteś i mogą wyświetlać Ci treści, które tylko Ty widzisz. Dzięki rozszerzonemu udostępnianiu tożsamości możesz dostarczyć te informacje do dowolnej odwiedzanej witryny z poziomu swojej matrycy.
**Wiele profili**
Możliwość tworzenia wielu profili, które są widoczne tylko dla określonych osób lub grup. Twój profil domyślny może być widoczny dla każdego, ale wszystkie profile dodatkowe mogą zawierać inne lub dodatkowe informacje i mogą być widoczne tylko dla tych, do których jest przypisany.
**Strony internetowe**
Zapewnia możliwość korzystania z funkcji projektowania stron internetowych i tworzenia niestandardowych stron internetowych na podstawie własnej zawartości, a także projektowania stron z układami stron, niestandardowymi elemntami menu i blokami treści.
Dodatkowe ustawienia dostępne tylko z wiersza poleceń
-----------------------------------------------------
Oprócz opcji konfiguracyjnych dostępnych w panelu administracyjnum, $Projectname zawiera wiele opcji, które są dostępne tylko z poziomu powłoki. Są to na ogół opcje uważane za zbyt niszowe, zaawansowane lub mogące być źle interpretowane przez zwykłych użytkowników.
**Prywatne notatki**
Ich omówienie znajduje się na stronie [Zaawanasowana konfiguracja dla administratorów](/doc/pl/hidden_configs).
Na stronach, na których jest to dostępne (Twoja matryca i osobiste strony internetowe), zapewnia widżet do tworzenia i przechowywania osobistych przypomnień i notatek.
**Ulepszone albumy ze zdjęciami**
Zapewnia przeglądarkę albumów zdjęć, która ma nieco ładniejszy interfejs niż zwykły album.
**Rozszerzone udostępnianie tożsamości**
Domyślnie Twoja tożsamość "podróżuje" z Tobą, gdy przeglądasz matrycę zdalnych witryn - tam też wiedzą kim jesteś i mogą wyświetlać Ci treści, które tylko Ty widzisz. Dzięki rozszerzonemu udostępnianiu tożsamości możesz dostarczyć te informacje do dowolnej odwiedzanej witryny z poziomu swojej matrycy.
**Tryb ekspercki**
Pozwala to zobaczyć niektóre zaawansowane opcje konfiguracji, które mogą dezorientować niektóre osoby lub powodować problemy z obsługą. Funkcjonalność ta może zapewnić pełną kontrolę nad funkcjami i kolorami motywu - dzięki czemu można dostosować dużą liczbę ustawień motywu wyświetlania do własnych upodobań.
**Kanał Premium**
Dzięki temu możesz ustawić ograniczenia i warunki dotyczące tych, które łączą się z Twoim kanałem. Może to być używane przez celebrytów lub kogoś, kto chce postawić jakieś warunki osobom, które chcą się połączyć z tym kanałe. Jednym z warunków moze byc dokonanie płatności za połączenie.
**Edytor tekstu formatowanego**
Edytor postów dostępny z poziomy matrycy jest edytorem zwykłego tekstu, ale matryca pozwala na stosowanie szerokieo zakresu znaczników przy użyciu BBcode. Edytor wizualny jest natomiast edytorem WYSIWIG (what you see is what you get - otrzymujesz to, co widzisz)i zapewnia wszystkie najczęściej używane znaczniki BBcode.
**Podgląd wpisu**
Umożliwia podgląd postów i komentarzy dokładnie tak, jak wyglądałyby na stronie przed ich opublikowaniem.
**Źródła kanałów**
Automatycznie importuje i ponownie publikuje zawartość kanału z innych kanałów lub źródeł. Umożliwia to tworzenie podkanałów i superkanałów z treści publikowanych gdzie indziej. Zasady są takie, że treść musi być publiczna, a właściciel kanału musi udzielić Ci pozwolenia na pozyskiwanie swojego kanału.
**Jeszcze więcej szyfrowania**
Stadardowo, prywatne wiadomości są szyfrowane podczas transportu i przechowywania. W dzisiejszych czasach to szyfrowanie może nie wystarczyć, jeśli twoja komunikacja jest wyjątkowo wrażliwa. Ta opcja umożliwia dodatkowo szyfrowanie treści "end-toend" za pomocą wspólnego tajnego klucza. Sposób, w jaki odbiorca pozna tajny klucz, zależy wyłącznie od Ciebie. Możesz podać wskazówkę, na przykład "imię pierwszego psa cioci Kloci".
**Wyszukiwanie wg daty**
Daje to możliwość wybierania postów według zakresów dat
**Filtr grup prywatności**
Włączenie tego widżetu umożliwia wyświetlanie strumienia postów tylko z wybranych grup połączeń. Powoduje to również przełączenie uprawnień wychodzących podczas przeglądania grupy prywatności. Jest to podobne do "kręgów" Google czy też "aspektów" w Disaporze.
**Zapisane wyszukiwania**
Udostępnia widżet wyszukiwania na stronie matrycy, który może zapisywać wybrane frazy wyszukiwania do ponownego wykorzystania.
**Zakładka Osobiste**
Włącz tą kartę, aby wyświetlać tylko wpisy matrycowe, z którymi w jakiś sposób wchodziłeś w interakcję, jako autor lub współautor konwersacji.
**Zakładka Nowy**
Włącza tą kartę, aby wyświetlać wszystkich nowych działania matrycy jako węża strażackiego lub osi czasu.
**Narzedzia zaprzyjaźnienia**
Filtrowanie aktywności strumienia matrycy według głębokości relacji.
**Edytuj wysłane posty**
Mozliwość edytowania i poprawiania postów i komentarzy juz po wysłaniu.
**Tagowanie**
Możliwość tagowania istniejących postów, w tym napisanych przez innych.
**Kategorie postów**
Możliwość dodawania kategorie do postów na swoim kanale
**Zapisane foldery**
Możliwość umieszczania postów w folderach lub tagach do późniejszego przywołania.
**Dezaprobata postów**
Możliwość dezaprobaty ("niepolubienia") wpisów i komentarzy.
**Gwiazdkowanie postów**
Możliwość oznaczania specjalnych postów znakiem gwiazdki
**Chmura tagów**
Udostępnienie osobistej chmury tagów na stronie swojego kanału
#include doc/macros/pl/main_footer.bb;

260
doc/pl/Plugins.md Normal file
View File

@@ -0,0 +1,260 @@
Tworzenie wtyczek (dodatków) do $Projectname
============================================
Przypuszczalnie chcesz, aby $Projectname zrobił coś, czego jeszcze nie robi. Jest wiele sposobów. Ale nauczmy się, jak napisać wtyczkę lub dodatek.
W katalogu $Projectname prawdopodobnie zobaczysz podkatalog o nazwie "addon". Jeśli jeszcze go nie masz, utwórz go.
mkdir addon
Następnie wymyśl nazwę swojego dodatku. Prawdopodobnie masz już jakieś pojęcie o tym, co chcesz, aby robił. Na potrzeby naszego przykładu utworzymy wtyczkę o nazwie "randplace", która zapewni nieco losową lokalizację każdego z Twoich wpisów. Nazwa wtyczki będzie służyć do znajdowania funkcji, które trzeba użyć i jest częścią nazwy każdej z tychfunkcji, więc dla bezpieczeństwa używaj tylko prostych znaków tekstowych.
Po wybraniu nazwy wtyczki, utwórz katalog wewnątz 'addon', aby przechowywać tu pliki wtyczki.
mkdir addon/randplace
Teraz utwórz plik wtyczki. Musi mieć taką samą nazwę i jest to skrypt PHP, więc za pomocą swojego ulubionego edytora utwórz plik
addon/randplace/randplace.php
Pierwszą linią tego pliku musi być fraza
<?php
Następnie utworzymy blok komentarza, aby opisać wtyczkę. Jest do tego specjalny format. Używamy / * ... * / w stylu komentarza i niektórych oznaczonych linii składających się z
/**
*
* Name: Random Place (here you can use better descriptions than you could in the filename)
* Description: Sample $Projectname plugin, Sets a random place when posting.
* Version: 1.0
* Author: Mike Macgirvin <mike@zothub.com>
*
*/
Te atrybuty będą widoczne dla administratora strony, gdy instaluje lub zarządza wtyczkami z panelu administracyjnego. Może być więcej autorów. W takim przypadku, po prostu dodaj kolejną linię zaczynającą się od "Autor:".
Typowa wtyczka będzie miała co najmniej następujące funkcje:
* pluginname_load()
* pluginname_unload()
W naszym przypadku nazwiemy je `randplace_load()` i `randplace_unload()`, bo taka jest nazwa naszej wtyczki. Te funkcje są wywoływane za każdym razem, gdy chcemy zainicjować wtyczkę lub usunąć ją z bieżącej strony internetowej. Również jeśli wtyczka wymaga rzeczy takich jak zmiana schematu bazy danych przed uruchomieniem jej po raz pierwszy, trzeba będzie umieścić poniższe funkcje:
* pluginname_install()
* pluginname_uninstall()
Następnie omówimy **zaczepy**. Zaczepy (*ang. hooks*) to miejsca w kodzie $Projectname, do których można "podczepić" kod wtyczki, aby go tam wykonywać. Zwykle wykorzystuje się funkcję `pluginname_load()` do zarejestrowania "funkcji obsługi" dla potrzebnych zaczepów. Następnie, gdy zostanie wyzwolony którykolwiek z tych zaczepów, zostanie wywołany podpięty tam kod.
Zarejestrujmy więc program obsługi zaczepów za pomocą funkcji `register_hook()`. Potrzebne są trzy argumenty. Pierwszy to nazwa zaczepu, który chcemy obsłużyć, drugi to nazwa pliku, który ma znaleźć naszą funkcję obsługi (ścieżka względem katalogu instalacyjnego $Projectname), a trzeci to nazwa funkcji. Stwórzmy więc teraz naszą funkcję `randplace_load()`.
```
function randplace_load() {
register_hook('post_local', 'addon/randplace/randplace.php', 'randplace_post_hook');
register_hook('feature_settings', 'addon/randplace/randplace.php', 'randplace_settings');
register_hook('feature_settings_post', 'addon/randplace/randplace.php', 'randplace_settings_post');
}
```
Tak więc przechwycimy trzy zdarzenia: `post_local`, które jest wywoływane, gdy w systemie lokalnym pojawia się wpis, `feature_settings`, aby ustawić pewne preferencje dla naszej wtyczki, oraz `feature_settings_post`, aby przechowywać te ustawienia.
Następnie utworzymy funkcję unload. Jest to łatwe, ponieważ wystarczy wyrejestrować nasze zaczepy. Wymaga to dokładnie tych samych argumentów.
```
function randplace_unload() {
unregister_hook('post_local', 'addon/randplace/randplace.php', 'randplace_post_hook');
unregister_hook('feature_settings', 'addon/randplace/randplace.php', 'randplace_settings');
unregister_hook('feature_settings_post', 'addon/randplace/randplace.php', 'randplace_settings_post');
}
```
Zaczepy są wywoływane z dwoma argumentami. Pierwszą to zawsze $a, który jest naszą globalną strukturą aplikacji i zawiera ogromną ilość informacji o stanie przetwarzanego żądania HTTP; a także o tym kim jest przeglądający i jaki jest nasz stan logowania oraz aktualną zawartość strony internetowej, którą prawdopodobnie tworzymy.
Drugi argument jest specyficzny dla zaczepu, który chce się wywołać. Zawiera informacje istotne dla tego konkretnego miejsca w programie i często pozwala na jego przegląd a nawet zmianę. Aby to zmienić, trzeba dodać zanak "&" do nazwy zmiennej, aby była przekazywana do funkcji przez odniesienie. W przeciwnym razie utworzona zostanie kopia i wszelkie wprowadzone zmiany zostaną utracone przy ponownym przetworzeniu zaczepu. Zwykle (ale nie zawsze) drugim argumentem jest nazwana tablica struktur danych.
Dodajmy więc poniższy kod, aby zaimplementować nasz moduł obsługi zaczepu:
```
function randplace_post_hook($a, &$item) {
/**
*
* W systemie lokalnym został wpisany jakiś element.
* Będziemy wyszukiwać określonych elementów:
* - Wpis napisany przez właściciela profilu
* - Właściciel profilu musi zezwolić na naszą wtyczkę
*
*/
logger('randplace invoked');
if(! local_channel()) /* nie zero jeśli zalogowany jest użytkownik systemu */
return;
if(local_channel() != $item['uid']) /* Czy ta osoba jest właścicielem wpisu? */
return;
if(($item['parent']) || (! is_item_normal($item))) {
/* Jeśli element ma rodzica lub nie jest „normalny”, jest to komentarz lub coś innego, a nie wpis. */
return;
}
/* Pobranie osobistych ustawień konfiguracyjnych */
$active = get_pconfig(local_channel(), 'randplace', 'enable');
if(! $active)
return;
/**
*
* OK, wolno nam robić swoje.
* Oto, co zamierzamy zrobić:
* załadowanie listy nazw stref czasowych i użycie jej do wygenerowania listy miast na świecie.
* Następnie wybierzemy losowo jedno z nich i umieścimy je w polu "location" wpisu.
*
*/
$cities = array();
$zones = timezone_identifiers_list();
foreach($zones as $zone) {
if((strpos($zone,'/')) && (! stristr($zone,'US/')) && (! stristr($zone,'Etc/')))
$cities[] = str_replace('_', ' ',substr($zone,strpos($zone,'/') + 1));
}
if(! count($cities))
return;
$city = array_rand($cities,1);
$item['location'] = $cities[$city];
return;
}
```
Teraz dodajmy nasze funkcje do ustawień preferencji tworzenia i przechowywania.
```
/**
*
* Wywołanie zwrotne z funkcji ustawień wpisu.
* $post zawiera globalną tablicę $_POST.
* Upewnimy się, że mamy ważne konto użytkownika
* i że kliknięto tylko nasz własny przycisk submit
* a jeśli tak, to ustawiamy ustawienia konfiguracyjne dla tego użytkownika.
*
*/
function randplace_settings_post($a,$post) {
if(! local_channel())
return;
if($_POST['randplace-submit'])
set_pconfig(local_channel(),'randplace','enable',intval($_POST['randplace']));
}
/**
*
* Wywoływanie z formularza ustawień funkcjonalności.
* Drugim argumentem jest w tym przypadku łańcuch, region treści HTML strony.
* Dodanie własnych informacje o ustawieniach do tego łańcucha.
*
* Aby zapewnić jednolitość stron ustawień, stosujemy następującą konwencję
* <div class="settings-block">
* <h3>title</h3>
* .... settings html - będzie wiele elementów pływających ...
* <div class="clear"></div> <!-- klasa ogólna, która czyści wszystkie elementy pływające -->
* <input type="submit" name="pluginnname-submit" class="settings-submit" ..... />
* </div>
*/
function randplace_settings(&$a,&$s) {
if(! local_channel())
return;
/* Dodanie naszego arkusza stylów do strony, aby ładnie wyglądała strona ustawień */
head_add_css('/addon/randplace/randplace.css');
/* Pobranie aktualnego stan naszej zmiennej konfiguracyjnej */
$enabled = get_pconfig(local_channel(),'randplace','enable');
$checked = (($enabled) ? ' checked="checked" ' : '');
/* Dodaj trochę HTML do istniejącego formularza */
$s .= '<div class="settings-block">';
$s .= '<h3>' . t('Randplace Settings') . '</h3>';
$s .= '<div id="randplace-enable-wrapper">';
$s .= '<label id="randplace-enable-label" for="randplace-checkbox">' . t('Enable Randplace Plugin') . '</label>';
$s .= '<input id="randplace-checkbox" type="checkbox" name="randplace" value="1" ' . $checked . '/>';
$s .= '</div><div class="clear"></div>';
/* dodanie przycisku przesyłania */
$s .= '<div class="settings-submit-wrapper" ><input type="submit" name="randplace-submit" class="settings-submit" value="' . t('Submit') . '" /></div></div>';
}
```
***Zaawansowane wtyczki***
Czasami zachodzi potrzeba zapewnienia jakichś nowych funkcji, których w ogóle nie ma lub których nie można zapewnić za pomocą zaczepów. W tym przypadku wtyczka może również działać jako "moduł". Moduł w naszym przypadku odnosi się do ustrukturyzowanej procedury obsługi strony internetowej, która odpowiada na podany adres URL. Wtedy wszystko, co uzyskuje dostęp do tego adresu URL, będzie obsługiwane w całości przez wtyczkę.
Kluczem do tego jest stworzenie prostej funkcji o nazwie `pluginname_module()`, która nic nie robi.
```
function randplace_module() { return; }
```
Gdy ta funkcja już istnieje, adres URL https://twoja_witryna/randplace będzie uzyskiwał dostęp do wtyczki jako modułu. Następnie możesz zdefiniować funkcje, które są wywoływane w różnych miejscach w celu zbudowania strony internetowej, tak jak moduły w katalogu mod/. Oto typowe funkcje i kolejność ich wywoływania
```
modulename_init($a) // (e.g. randplace_init($a);) wywoływana jako pierwsza.
// Gdy chce się emitować json lub xml, powinno się to
// zrobić tutaj, a następnie wywołać killme(), co pozwoli
// uniknąć domyślnej akcji budowania strony internetowej.
modulename_aside($a) // często uzywana di tworzenia zawartości paska bocznego
modulename_post($a) // wywoływana za każdym razem, gdy strona jest otwierana
// za pomocą metody "post"
modulename_content($a) // wywoływana w celu wygenerowania zawartości strony centralnej.
// Ta funkcja powinna zwracać łańcuch znaków składający się
// z centralnej yteści strony.
```
Funkcje modułu mają dostęp do ścieżki URL tak, jakby były samodzielnymi programami w systemie operacyjnym Unix. Dla przykładu, w naszego module stwórzmy coś co działa pod adresem:
https://yoursite/randplace/something/somewhere/whatever
Bedzie to listę argc i argv do wykorzystania przez funkcje tego modułu
```
$x = argc(); $x will be 4, the number of path arguments after the sitename
for($x = 0; $x < argc(); $x ++)
echo $x . ' ' . argv($x);
0 randplace
1 something
2 somewhere
3 whatever
```
***Przenoszenie wtyczek Friendica***
$Projectname wykorzystuje podobną architekturę wtyczek do projektu Friendica. Mechanizmy uwierzytelniania, tożsamości i uprawnień są zupełnie inne. Wiele wtyczek Friendica można stosunkowo łatwo przenosić, zmieniając nazwy kilku funkcji i następnie zapewniając przestrzeganie modelu uprawnień. Funkcje, których nazwy wymagają zmiany, to:
* Funkcja Friendica `pluginname_install()` to `pluginname_load()`
* Funkcja Friendica `pluginname_uninstall()` to `pluginname_unload()`
$Projectname ma funkcje `_install` i `_uninstall`, ale są one używane w inny sposób.
* Funkcja zaczepu w Friendica `plugin_settings` ma nazwę `feature_settings`
* Funkcja zaczepu Friendica `plugin_settings_post` ma nazwę `feature_settings_post`
Zmiana tych ustawień często pozwoli na działanie wtyczki, ale proszę dokładnie sprawdzić wszystkie uprawnienia i kod identyfikacyjny, ponieważ koncepcje, które za tym stoją, są zupełnie inne w $Projectname. Wiele nazw danych strukturalnych (zwłaszcza kolumny schematu bazy danych) jest również zupełnie inna.
#include doc/macros/main_footer.bb;

View File

@@ -0,0 +1,43 @@
#Katalog główny#
Domyślnie $Projectname używa katalogów dostępnych w Internecie, które funkcjonują jako kanały.
Istnieją pewne scenariusze, w których może być potrzebny własny serwer katalogów, do którego można by podłączyć wiele węzłów. Ogranicza to dostęp tylko do kanałów w węzłach podłączonych do tego serwera katalogowego.
##Instrukcje dotyczące konfigurowania jednego węzła jako katalogu podstawowego dla wielu węzłów prywatnych.##
***
* W węźle, który będzie serwerem katalogów, otwórz plik .htconfig.php i ustaw:
`App::$config['system']['directory_mode'] = DIRECTORY_MODE_PRIMARY;`
Domyślnie, opcja ta powinna już być ustawiona na **DIRECTORY_MODE_NORMAL**, więc po prostu wystarczy tylko ustawić nową wartość: **DIRECTORY_MODE_PRIMARY**
* Następnie, w każdym węźle (w tym na serwerze katalogowym), w terminalu, przejdź do folderu, w którym jest zainstalowany kod węzła i uruchomić usługę katalogową:
`util/config system directory_realm YOURREALMNAME`
(**YOURREALMNAME** może być dowolną nazwą dziedziny katalogowej)
po czym:
`util/config system realm_token THEPASSWORD`
(**THEPASSWORD** jest hasłem dla dziedziny katalogowej)
**UWAGA:** Trzeba użyć tej samej nazwy dziedziny i hasła dla każdego węzła
* Na koniec, dla każdego węzła "klienckiego", uruchom (z terminala):
`util/config system directory_server https://theaddressofyourdirectoryserver.com`
***
Teraz, gdy przeglądasz katalog każdego węzła, powinien on pokazywać tylko kanały, które istnieją w węzłach ustawionej domeny katalogowej. Do tej pory testowałem to z dwoma węzłami i wydaje się, że działa dobrze.
Kanały utworzone w każdym węźle są odzwierciedlane w katalogu głównym, a następnie w katalogu wszystkich węzłów klienckich
##Problemy##
***
Kiedy tworzyłem pierwszy węzeł, był on uruchomiony i działał przez około godzinę, zanim zmieniłem go na PRIMARY_MODE, a po zmianie w katalogu nadal było kilka kanałów z całej matrycy. Usunąłem je z tabeli xchan i wydaje się, że rozwiązało to problem.

View File

@@ -1,56 +1,80 @@
Tłumaczenie $Projectname
========================
Procedura tłumaczenia
---------------------
Procedura tłumaczenia na język polski
-------------------------------------
Ciągi używane w interfejsie użytkownika $Projectname są tłumaczone
w [Transifex][1], a następnie przeniesione do repozytorium Git na
github. Jeśli chcesz pomóc w tłumaczeniu dla dowolnego języka, czy
to poprawianie warunków, czy tłumaczenie $Projectname na plik aktualnie
nieobsługiwany język, zarejestruj konto na transifex.com i skontaktuj
się z tamtejszym zespołem tłumaczy Redmatrix.
Tłumaczenie interfejsu użytkownika, ekranów kontekstowej pomocy oraz dokumentacji
na język polski odbiega nieco od ogólnej procedury przyjetej w $Projectname.
Po prostu, zrezygnowano z przygotowania pliku translacyjnego hmessages.po
za pośrednictwem serwisu [Transifex][1], tak jak to jest zalecane w $Projectname
i posłużono się sporządzeniem tych plików przy pomocy ogólnie dostępnych narzędzi
translacyjnych przeznaczonych do tworzenia plików [gettext](https://www.gnu.org/software/gettext/) (rozszerzenia .po, .mo, .pot), takich jak [poedit](https://poedit.net/) i inne.
Tłumaczenie $Projectname jest proste. Po prostu użyj narzędzia online
w transifex. Jeśli nie chcesz mieć do czynienia z git & co. w porządku,
regularnie sprawdzamy status tłumaczeń i importujemy je do drzewa
źródłowego na github, aby inni mogli z nich korzystać.
Trzeba podkreślić, że to odstępstwo dotyczy przygotowania pliku hmessages.po
i organizacji prac nad tłumaczeniem.
Nie uwzględniamy każdego tłumaczenia z transifex w drzewie źródłowym,
aby uniknąć rozproszonego i zakłóconego ogólnego doświadczenia. Jako
niewykształcone przypuszczenie mamy dolną granicę 50% przetłumaczonych
ciągów, zanim włączymy język. Limit ten jest oceniany tylko na podstawie
ilości przetłumaczonych ciągów przy założeniu, że najbardziej widoczne
ciągi dla interfejsu użytkownika zostaną przetłumaczone jako pierwsze
przez zespół tłumaczący. Jeśli uważasz, że Twoje tłumaczenie będzie
przydatne przed tym limitem, skontaktuj się z nami, a prawdopodobnie
uwzględnimy pracę Twoich zespołów w drzewie źródłowym.
Tłumaczenie $Projectname na język polski jest obecnie wydzielone w odrębny podprojekt,
utrzymywany w [repozytorium na GitHub](https://github.com/astabski/hubzilla-pl)
Jeśli chcesz samodzielnie przenieść swoją pracę do drzewa źródłowego,
zrób to i skontaktuj się z nami i zadaj pytanie, które się pojawi.
Proces jest prosty, a oprogramowanie $Projectname jest dostarczane ze wszystkimi
niezbędnymi narzędziami.
Projekt ten obejmuje wszystkie pliki potrzebne do przetłumaczenia interfesju użytkownika,
pomocy kontekstowej i oficjalnej dokumentacji, zawarte w następujących katalogach
kodu $Projectname:
Lokalizacją przetłumaczonych plików jest w drzewie źródłowym katalog
`/view/LNG-CODE/`, ggdzie LNG-CODE jest używanym kodem języka, np.
`de` dla niemieckiego lub `fr` dla francuskiego.
W przypadku szablonów wiadomości e-mail (pliki `*.tpl`) po prostu umieść
je w katalogu i gotowe. Przetłumaczone łańcuchy pochodzą z pliku
"hmessages.po" z transifex, który należy przetłumaczyć na plik PHP
używany przez $Projectname. Aby to zrobić, umieść plik w wymienionym
wyżej katalogu i użyj narzędzia `po2php` z katalogu `util` w instalacji
$Projectname.
- view/pl
- doc/context/pl
- doc/macros/pl
- doc/pl
Zakładając, że chcesz przetłumaczyć niemiecką wersję umieszczoną pliku
`view/de/hmessages.po`, wykonaj następujące czynności.
Projekt ten jest obecnie podstawą oficjalnego polskiego tłumaczenia $Projectname.
Po każdej istotnej zmianie, osoba kierująca projektem tłumaczenia zgłasza odpowiednie
żądanie PR do drzewa żródłowego $Projectname.
### Zgłaszanie poprawek
Jeśli chcesz zgłosić jakieś zmiany w istniejącym tekście tłumaczenia, otwórz
nową sprawę na stronie https://github.com/astabski/hubzilla-pl/issues i podaj tam
szczegóły proponowanych zmian.
Możesz też dokonać poprawek w tym projekcie, zgłaszając odpowiednio przygotowane
żądanie PR.
### Nowe tłumaczenia
Jeśli chcesz pomóc, tworząc tłumaczenia jeszcze nie przetłumaczonych dokumentów
$Projectname, dołącz do projektu https://github.com/astabski/hubzilla-pl. W tym
celu umieść na stronie https://github.com/astabski/hubzilla-pl/issues odpowiednią
wiadomość. Otrzymasz odpowiedź z dokładną instrukcją.
Ogólne zasady tłumaczeń obowiązujące w $Projectname
---------------------------------------------------
Jeśli chcesz samodzielnie przenieść swoją pracę do drzewa źródłowego $Projectname,
skontaktuj się z zespołem $Projectname i zadaj pytania.
Proces jest tłumaczenia prosty, a oprogramowanie $Projectname jest dostarczane ze
wszystkimi niezbędnymi narzędziami.
Lokalizacją przetłumaczonych plików jest w kodzie źródłowym katalog `/view/LNG-CODE/`,
gdzie `LNG-CODE` jest używanym kodem języka, np. `de` dla niemieckiego lub `fr`
dla francuskiego.
W przypadku szablonów wiadomości e-mail (pliki `*.tpl`) po prostu trzeba umieścić
je w katalogu i gotowe. Przetłumaczone łańcuchy pochodzą z pliku `hmessages.po`
z serwisu Transifex, który należy przetłumaczyć na plik PHP używany przez $Projectname.
Aby to zrobić, trzeba umieścić plik w wymienionym wyżej katalogu i użyć narzędzia
`po2php` z katalogu `util` w instalacji $Projectname.
Zakładając, że chcesz przetłumaczyć polską wersję umieszczoną pliku
`view/pl/hmessages.po`, wykonaj następujące czynności.
1. Przejdź w wierszu polecenia do katalogu głównego instalacji $Projectname
2. Wykonaj skrypt `po2php`, który jest umieszczono tłumaczenia dla pliku `hstrings.php`, który jest używany w $Projectname.
$> php util/po2php.php view/de/hmessages.po
$> php util/po2php.php view/pl/hmessages.po
Dane wyjściowe skryptu zostaną umieszczone w `view/de/hstrings.php, gdzie
Dane wyjściowe skryptu zostaną umieszczone w `view/de/hstrings.php, bo tam
froemdoca oczekuje tego pliku, więc możesz natychmiast przetestować swoje
tłumaczenie.

171
doc/pl/Widgets.md Normal file
View File

@@ -0,0 +1,171 @@
Rdzenne widżety
===============
Niektóre z tych widżetów ma ograniczenia, które mogą ograniczać typ strony, na której można umieszczać widżet lub mogą wymagać logowania
* clock - wyświetla aktualny czas
* args: military (1 or 0) - use 24 hour time as opposed to AM/PM
<br />&nbsp;<br />
* profile - wyświetla boczny pasek profilu na stronach, które ładują profile (strony z pseudonimem w adresie URL)
* tagcloud - wyświetla tagcloud elementów strony
* args: count - liczba elementów do jednoczesnego wyświetlenia (domyślnie 24)
<br />&nbsp;<br />
* collections - selektor grupy prywatności dla aktualnie zalogowanego kanału
* args: mode - może to być "conversation", "group" albo "abook" w zależności od modułu
<br />&nbsp;<br />
* suggestions - sugestie znajomych dla aktualnie zalogowanego kanału
* follow - przedstawia pole tekstowe do śledzenia innego kanału
* notes - obszar prywatnych notatek dla aktualnie zalogowanego kanału, jeśli funkcja private_notes jest włączona
* savedsearch - wyszukiwanie sieci lub matrycy z zapisem - trzeba być zalogowanym i musi być włączona funkcjonalność savedsearch
* filer - wybór elementów pola ze strumienia sieci lub matrycy - musi się być zalogowanym
* archive - selektor zakresu dat dla stron sieci i kanałów
* args: 'wall' - 1 or 0, ograniczenie do wpisów ściennych lub wpisów sieciowych/matrycowych (domyślnie)
<br />&nbsp;<br />
* fullprofile - taki sam jak obecny profil
* categories - filtr kategorii (strona kanału)
* tagcloud_wall - tagcloud tylko dla strony kanału
* args: 'limit' - ilość tagów do wyświetlenie (domyślnie 50)
<br />&nbsp;<br />
* catcloud_wall - tagcloud dla kategorii stron kanału
* args: 'limit' - liczba kategorii do wyświetlenia na jednej stronie (domyślnie 50)
<br />&nbsp;<br />
* affinity - suwak powinowactwa na stronie sieciowej, trzeba być zalogowanym
* settings_menu - menu paska bocznego dla strony ustawień, trzeba być zalogowanym
* mailmenu - menu paska bocznego dla strony z prywatnymi wiadomościami, trzeba sie zalogować
* design_tools - menu narzędzi projektowych do tworzenia stron internetowych, trzeba sie zalogować
* findpeople - narzędzia do wyszukiwania innych kanałów
* photo_albums - wyświetla listę albumów ze zdjęciami aktualnego właściciela strony za pomocą menu wyboru
* vcard - mini pasek boczny profilu dla osoby, którą się jest zainteresowanym (właściciel strony, cokolwiek)
* dirsafemode - narzędzie do wyboru katalogu - tylko na stronach katalogów
* dirsort - narzędzie do wyboru katalogu - tylko na stronach katalogów
* dirtags - narzędzie katalogowe - tylko na stronach katalogów
* menu_preview - wyświetlanie podgląd menu - tylko na stronach edycji menu
* chatroom_list - lista czatów dla właściciela strony
* bookmarkedchats - lista zakładek do czatów zebranych na tej stronie dla obecnego obserwatora
* suggestedchats - "ciekawe" czaty wybrane dla obecnego obserwatora
* item - wyświetla pojedynczą stronę internetową zgodnie z argumentem mid lub title
* args:
* channel_id - kanał, do którego należy treść, domyślnie jest to profile_uid
* mid - message_id strony do wyświetlenia (musi być to strona internetowa a nie element konersacji)
* title - argument title w adresie URL strony internetowej (musi zawierać tutuł lub mid)
<br />&nbsp;<br />
* photo - wyświetla pojedyncze zdjęcie
* args:
* url - adres URL zdjęcia, musu zawierać schemat http lub https
* zrl - uwierzytelniony link zid
* style - łańcuch stylu CSS
<br />&nbsp;<br />
* cover_photo - wyświetla zdjęcie okładkowe dla wybranego kanału
* args:
* channel_id - zastosowany kanał, domyślnie jest to profile_uid
* style - łańcuch stylu CSS (domyślnie jest dynamicznie ustawiane na szerokość regionu)
<br />&nbsp;<br />
* photo_rand - wyświetla losowe zdjęcie z jednego z albumów fotograficznych. Honorowane są uprawnienie dostępu do zdjęć
* args:
* album - nazwa albumu (bardzo gorąco zalecane, jeśli ma się dużo zdjęć)
* scale - zazwyczaj 0 (oryginalna wielkość), 1 (1024px), 2, (640px) lub 3 (320px)
* style - łańcuch stylu CSS
* channel_id - jeśli nie Twój
<br />&nbsp;<br />
* random_block - wyświetlić losowy element blokowy z kolekcji narzędzi do projektowania stron internetowych. Honorowane są uprawnienia dostępu.
* args:
* contains - zwraca tylko bloki, które zawierają łańcuch cotains w nazwie bloku
* channel_id - jeśłi nie Twój
<br />&nbsp;<br />
* tasklist - podać listę zadań lub spraw do załatwienia dla aktualnie zalogowanego kanału.
* args:
* all - jeśłi nie 0, to wyświetla ukończone zadania.
<br />&nbsp;<br />
* forums - podać listę połączonych forów publicznych z niewidocznymi liczbami dla aktualnie zalogowanego kanału.
<br />&nbsp;<br />
* activity - podać listę autorów nieprzeczytanych treści sieciowych dla aktualnie zalogowanego kanału.
* album - udostępnia widget zawierający pełny album ze zdjęciami z albumów należących do właściciela strony; może być zbyt duży, aby wyświetlić go w regionie paska bocznego, więc najlepiej jest zaimplementować to jako widżet obszaru treści.
* args:
* album - nazwa albumu
* title - opcjonalny tytuł, używana jest nazwa albumu, jeśli nie jest dostęþna
<br />&nbsp;<br />
Tworzenie własnych widżetów
===========================
### Widżety oparty na klasie
Aby utworzyć widżet oparty, na przykład, na klasie o nazwie "slugfish", utwórz plik o następującej zawartości:
````
<?php
namespace Zotlabs\Widget;
class Slugfish {
function widget($args) {
... Wstaw tutaj kod widżetu.
... Funkcja ta zwraca łańcuch, który jest treścią HTML widżetu.
... $args to nazwa tablicy, która przekazuje sowolne zmienne [var] z edytora układu
... Na przykład [widget=slugfish][var=count]3[/var][/widget] wypełni $args tak:
... [ 'count' => 3 ]
}
````
Wynikowy plik można umieścić w widget/Slugfish/Slugfish.php lub Zotlabs/SiteWidgets/Slugfish.php. Można go również połączyć z repozytorium git za pomocą pliku util/add_widget_repo.
### Tradycyjny widget oparty na funkcjach
Jeśli chcesz mieć widżet o nazwie, na przykład, "slugfish", utwórz `widget/widget_slugfish.php` zawierający
<?php
function widget_slugfish($args) {
.. wstaw tu kod widżetu. Zobacz powyższe informacje o widżetach opartych na klasie, aby uzyskać szczegółowe informacje.
}
#include doc/macros/main_footer.bb;

View File

@@ -1,7 +1,11 @@
[h3]Co to jest $Projectname?[/h3]
$Projectname to bezpłatny i otwartoźródłowy zestaw aplikacji i usług internetowych działających na specjalnym serwerze internetowym, zwanym "hubem", który może łączyć się z innymi hubami w sfederalizowanej sieci internetowej.
$Projectname zapewnia użytkownikom zaawansowaną komunikację, tożsamości i usług kontroli dostępu, które bezproblemowo współpracują w różnych domenach i niezależnych witrynach internetowych. Pozwala użytkownikom [b]publicznie[/b] lub [b]prywatnie[/b] publikować treści za pośrednictwem "kanałów" (ang. channel), które podstawowymi, zabezpieczonymi kryptograficznie tożsamościami zapewniającymi uwierzytelnianie niezależnie od hubów, które je hostują. To rewolucyjne wyzwolenie tożsamości online z poszczególnych serwerów i domen jest nazywane "tożsamością nomadyczną" i jest oparte na protokole Zot, nowej strukturze zdecentralizowanej kontroli dostępu ze szczegółowymi, rozszerzalnymi uprawnieniami.
Z praktycznego punktu widzenia członków danego huba, korzystających z oprogramowania $Projectname, oferuje ono szereg znanych, zintegrowanych aplikacji i usług internetowych, w tym:
$Projectname to bezpłatny i otwartoźródłowy zestaw aplikacji i usług internetowych działających na specjalnym serwerze internetowym, zwanym "węzłem", który może łączyć się z innymi węzłami w sfederalizowanej sieci internetowej.
$Projectname zapewnia użytkownikom zaawansowaną komunikację, tożsamości i usługę kontroli dostępu, które bezproblemowo współpracują w różnych domenach i niezależnych
serwisach internetowych. $Projectname pozwala użytkownikom publikować treści, [b]publicznie[/b] lub [b]prywatnie[/b], w swoich "kanałach" (ang. channels), które zabezpieczonymi kryptograficznie tożsamościami zapewniającymi
uwierzytelnianie uzytkowników niezależnie od węzłów, które hostują te kanały. To rewolucyjne uwolnienie tożsamości inernetowej z poszczególnych serwerów i domen jest nazywane "tożsamością nomadyczną" i jest oparte na protokole Zot - nowej strukturze
zdecentralizowanej kontroli dostępu ze szczegółowymi, rozszerzalnymi uprawnieniami.
Z praktycznego punktu widzenia członków danego węzła, korzystających z oprogramowania $Projectname, oferuje ono szereg znanych,
zintegrowanych aplikacji i usług internetowych, w tym:
[ul]
[li]wątki dyskusyjne w sieciach społecznościowych[/li]
[li]przechowywanie plików w chmurze[/li]
@@ -9,23 +13,30 @@ Z praktycznego punktu widzenia członków danego huba, korzystających z oprogra
[li]hosting stron internetowych z systemem zarządzania treścią[/li]
[li]wiki[/li]
[li]i dużo więcej ...[/li][/ul]
Chociaż wszystkie te aplikacje i usługi można znaleźć w innych pakietach oprogramowania, tylko $Projectname pozwala ustawić uprawnienia dla grup i osób, [b]które mogą nawet nie mieć kont na Twoim hubie[/b]! W typowych aplikacjach internetowych, jeśli chcesz udostępniać rzeczy prywatnie w Internecie, osoby, którym udostępniasz dane, muszą mieć konta na serwerze, na którym znajdują się Twoje dane; w przeciwnym razie serwer nie może uwierzytelniać odwiedzających witrynę, aby wiedzieć, czy przyznać im dostęp. $Projectname rozwiązuje ten problem za pomocą zaawansowanego systemu zdalnego uwierzytelniania, który weryfikuje tożsamość odwiedzających, wykorzystując techniki obejmujące kryptografię klucza publicznego.
Chociaż wszystkie te aplikacje i usługi można znaleźć w innych pakietach oprogramowania, tylko $Projectname pozwala ustawić uprawnienia dla grup i osób, [b]które mogą nawet nie mieć kont na Twoim węźle[/b]! W typowych aplikacjach internetowych, jeśli chcesz udostępniać rzeczy prywatnie w Internecie, osoby, którym udostępniasz dane, muszą mieć konta na serwerze, na którym znajdują się Twoje dane; w przeciwnym razie serwer nie może uwierzytelniać odwiedzających witrynę, aby wiedzieć, czy przyznać im dostęp. $Projectname rozwiązuje ten problem za pomocą zaawansowanego systemu zdalnego uwierzytelniania, który weryfikuje tożsamość odwiedzających, wykorzystując techniki obejmujące kryptografię klucza publicznego.
Dzięki oferowanym aplikacjom, $Projectname świetnie się nadaje do budowy platformy komunikacyjno-publikacyjnej o charkterze społecznościowym dla realnych grup społecznych, takich jak rodziny, lokalne grupy, organizacje społeczne, środowiska szkolne, wspólnoty mieszkańców czy wspólnoty religijne.
[h3]Stos programów[/h3]
Pakiet oprogramowania $Projectname jest stosunkowo standardową aplikacją serwerową napisaną głównie w PHP i MySQL i [url=https://framagit.org/$Projectname/core/blob/master/install/INSTALL.txt]wymagającą niewiele więcej niż serwera WWW, bazy danych zgodnej z MySQL i języka skryptowego PHP[/url]. System został zaprojektowany tak, aby był łatwy do zainstalowania przez osoby z podstawowymi umiejętnościami administrowania witryną, na typowych platformach współdzielonego hostingu, z uwzglednieniem szerokiej gamy sprzętu komputerowego. Można go również łatwo rozszerzyć za pomocą wtyczek i motywów oraz innych narzędzi innych firm.
Pakiet oprogramowania $Projectname jest stosunkowo standardową aplikacją serwerową napisaną głównie w PHP i MySQL,
[url=https://framagit.org/$Projectname/core/blob/master/install/INSTALL.txt]wymagającą niewiele więcej niż serwera WWW,
bazy danych zgodnej z MySQL i środowiska wykonawczego PHP[/url]. System został zaprojektowany tak, aby był łatwy do
zainstalowania przez osoby z podstawowymi umiejętnościami administrowania witryną, na typowych platformach współdzielonego
hostingu, z uwzglednieniem szerokiej gamy sprzętu komputerowego. Można go również łatwo rozszerzyć za pomocą wtyczek i motywów
oraz innych narzędzi zewnętrznych.
[h3]Słownik[/h3]
[dl terms="b"]
[*= hub ([i]ang. hub[/i])] Instancja tego oprogramowania działająca na standardowym serwerze WWW
[*= węzeł ([i]ang. hub[/i])] Instancja oprogramowania $Projectname działająca na standardowym serwerze WWW
[*= siatka, grid ([i]w oryginale ang., grid[/i])] Globalna sieć hubów, które wymieniają między sobą informacje za pomocą protokołu Zot. Nie to tylko huby oparte na $Projectname, ale wszystkie hubyy implementujace protokół Zot.
[*= si Zot, sieć ([i]w oryginale ang., grid[/i])] Globalna sieć węzłów, które wymieniają między sobą informacje za pomocą protokołu Zot. Nie to tylko węzły oparte na $Projectname, ale wszystkie węzły implementujace protokół Zot.
[*= kanał ([i]ang. channel[/i])] Techniczny odpowiednik tożsamości. Kanał może reprezentować osobę, blog lub forum, żeby wymienić tylko kilka. Kanały mogą łączyć się z innymi kanałami w celu udostępniania informacji z bardzo szczegółowymi uprawnieniami.
[*= kanał ([i]ang. channel[/i])] Forma organizacji treści i techniczny odpowiednik tożsamości. Kanał może mieć formę osobistej witryny internetowej, bloga, forum i innych znanych form publikowania treści. Kanały mogą łączyć się z innymi kanałami w celu udostępniania informacji z możliwością ustawiania bardzo szczegółowych uprawnień dostępu.
[*= klon ([i]ang. clone[/i])] Kanały mogą mieć klony powiązane z oddzielnymi i niepowiązanymi kontami w niezależnych hubach. Komunikacja współdzielona z kanałem jest synchronizowana między klonami kanału, co umożliwia kanałowi wysyłanie i odbieranie wiadomości oraz dostęp do współdzielonych treści z wielu hubów. Zapewnia to odporność na awarie sieci i sprzętu, które mogą stanowić poważny problem w przypadku serwerów WWW z własnym hostingiem lub o ograniczonych zasobach. Klonowanie umożliwia całkowite przeniesienie kanału z jednego huba do drugiego, zabierając ze sobą dane i połączenia. Zobacz "tożsamość nomadyczna".
[*= klon ([i]ang. clone[/i])] Kanały mogą mieć klony innych na innych niezależnych węzłach. Komunikacja współdzielona z kanałem jest synchronizowana między klonami kanału, co umożliwia kanałowi wysyłanie i odbieranie wiadomości oraz dostęp do współdzielonych treści z wielu węzłów. Zapewnia to odporność na awarie sieci i sprzętu, które mogą stanowić poważny problem w przypadku serwerów WWW utrzymywanych na prywatnych serwerach w hostingu współdzielonym lub o ograniczonych zasobach. Klonowanie umożliwia też całkowite przeniesienie kanału z jednego węzła na drugi, z zabraniem wszystkich danych i połączeń. Zobacz "tożsamość nomadyczna".
[*= tożsamość nomadyczna ([i]ang. nomadic identity[/i])] Możliwość uwierzytelniania i łatwej migracji tożsamości w niezależnych hubach i domenach internetowych. Tożsamość nomadyczna zapewnia prawdziwą własność tożsamości online, ponieważ tożsamości kanałów kontrolowanych przez konto w hubie nie powiązane z samym hubem. hub bardziej przypomina "hosta" kanałów. W serwisie $Projectname nie masz "konta" na serwerze, tak jak na typowych serwisach internetowych - posiadasz tożsamość, którą możesz przenosić ze sobą po całej siatce za pomocą klonów.
[*= konto ([i]ang. account[/i])] Umowny rejestr zawierajacy dane rejestracyjne i ewentualnie inne dane użytkownika serwisu internetowego, ściśle związane z umową jaką zwiera użytkownik z operatorem (właścicielem) serwisu o świadczenie usług drogą internetową. Posiadanie konta umożliwia użytkownikowi korzystanie z usług serwisu. Nie jest to pojęcie specyficzne dla platformy Hubzilla ale ma tu znaczenie węższe i należy go odróżniać od profilu lub tożsamości użytkownika. W Hubzilla, użytkownik (w ramach swojego konta) może mieć wiele tożsamości i te tożsamości utrzymywać na wielu odrębnych serwisach w sieci Zotm, w sposób zsynchronizowany. Na tych serwisach użytkownik musi mieć odrębne konta.
[*= tożsamość nomadyczna ([i]ang. nomadic identity[/i])] Możliwość uwierzytelniania i łatwej migracji tożsamości pomiędzy niezależnymi węzłami i domenami internetowymi. Tożsamość nomadyczna zapewnia prawdziwą własność tożsamości internetową, ponieważ tożsamości kontrolowane przez konto w węźle nie ściśle związane z węzłem. Węzeł bardziej przypomina "hosta" kanałów. W serwisie $Projectname nie masz "konta" na serwerze, tak jak na typowych serwisach internetowych - posiadasz tożsamość, którą możesz przenosić w całej sieci za pomocą mechanizmu klonowania.
[*= [url=[baseurl]/help/developer/zot_protocol]Protokół Zot[/url]] Nowy protokół, oparty na JSON, do wdrażania bezpiecznej, zdecentralizowanej komunikacji i usług. Różni się od wielu innych protokołów komunikacyjnych, budując komunikację na podstawie zdecentralizowanej struktury tożsamości i uwierzytelniania. Składnik uwierzytelniania jest koncepcyjnie podobny do OpenID, ale jest odizolowany od tożsamości opartej na DNS. Tam, gdzie to możliwe, zdalne uwierzytelnianie jest ciche i niewidoczne. Zapewnia to mechanizm kontroli dostępu rozproszonego na skalę sieci WWW, który jest dyskretny.
[/dl]
@@ -43,14 +54,14 @@ Gdy to zrobisz, narzędzie "Suwak zaprzyjaźnienia", które zwykle pojawia się
Suwak zaprzyjażnienia umożliwia natychmiastowe filtrowanie dużych ilości treści, pogrupowanych według poziomów zaprzyjaźnienia.
[h4]Filtrowanie połączeń (Connection Filtering)[/h4]
Masz możliwość precyzyjnego kontrolowania tego, co pojawia się w Twoim strumieniu za pomocą opcjonalnego "Filtra połączeń" ([i]ang. Connection Filter[/i]). Po włączeniu Edytor połączeń zapewnia dane wejściowe do wybierania kryteriów, które należy dopasować, aby uwzględnić lub wykluczyć określony post z określonego kanału. Gdy post został dopuszczony, wszystkie komentarze do tego posta dozwolone, niezależnie od tego, czy spełniają kryteria wyboru. Możesz wybrać słowa, które jeśli obecne, blokują post lub zapewniają, że zostanie uwzględniony w Twoim strumieniu. Wyrażenia regularne mogą być używane do jeszcze dokładniejszej kontroli, a także hasztagów, a nawet wykrytego języka postu.
Masz możliwość precyzyjnego kontrolowania tego, co pojawia się w Twoim strumieniu za pomocą opcjonalnego "Filtra połączeń" ([i]ang. Connection Filter[/i]). Po włączeniu Edytor połączeń zapewnia dane wejściowe do wybierania kryteriów, które należy dopasować, aby uwzględnić lub wykluczyć określony wpis z określonego kanału. Gdy wpis został dopuszczony, wszystkie komentarze do tego wpisu dozwolone, niezależnie od tego, czy spełniają kryteria wyboru. Możesz wybrać słowa, które jeśli obecne, blokują wpis lub zapewniają, że zostanie uwzględniony w Twoim strumieniu. Wyrażenia regularne mogą być używane do jeszcze dokładniejszej kontroli, a także hasztagów, a nawet wykrytego języka wpisu.
[h4]Listy kontrolne dostępu (Access Control Lists - ACL)[/h4]
Udostępniając zawartość, członkowie mają możliwość ograniczenia tego, kto widzi zawartość. Klikając na kłódkę pod polem udostępniania, można wybrać odbiorców postu, klikając ich nazwy.
Udostępniając zawartość, członkowie mają możliwość ograniczenia tego, kto widzi zawartość. Klikając na kłódkę pod polem udostępniania, można wybrać odbiorców wpisu, klikając ich nazwy.
Po wysłaniu, wiadomość będzie widoczna tylko dla nadawcy i wybranych odbiorców. Innymi słowami, wiadomość nie pojawi się na jakichkolwiek publicznych ścianach.
Listy kontroli dostępu mogą być stosowane do treści i postów, zdjęć, wydarzeń, stron internetowych, pokojów rozmów i plików.
Listy kontroli dostępu mogą być stosowane do treści i wpisów, zdjęć, wydarzeń, stron internetowych, pokojów rozmów i plików.
[h4]Jednokrotne uwierzytelnianie (Single Sign-on)[/h4]
Listy kontroli dostępu działają dla wszystkich kanałów w siatce dzięki naszej unikalnej technologii pojedynczego logowania. Większość linków wewnętrznych zapewnia token tożsamości, który można zweryfikować w innych witrynach $Projectname i wykorzystać do kontrolowania dostępu do prywatnych zasobów. Logujesz się raz do swojego centrum domowego. Następnie uwierzytelnianie we wszystkich zasobach serwisu $Projectname jest "magiczne".
@@ -62,7 +73,7 @@ Pliki można przesyłać do osobistego obszaru przechowywania za pomocą narzęd
Przechowuj zdjęcia w albumach. Wszystkie Twoje zdjęcia mogą być chronione listami kontroli dostępu.
[h4]Kalendarze zdarzeń[/h4]
Twórz zdarzenia i zadania oraz zarządzaj nimi, które mogą być również chronione za pomocą list kontroli dostępu. Wydarzenia można importować i eksportować do innego oprogramowania przy użyciu standardowego formatu vcalendar lub iCal i udostępniać w postach innym osobom. Wydarzenia urodzinowe automatycznie dodawane od znajomych i konwertowane na właściwą strefę czasową, dzięki czemu będziesz dokładnie wiedzieć, kiedy mają miejsce urodziny - bez względu na to, gdzie się znajdujesz na świecie w stosunku do osoby urodzonej w dniu urodzin. Wydarzenia zwykle tworzone za pomocą liczników obecności, dzięki czemu Twoi znajomi i kontakty mogą natychmiast [url=https://pl.wikipedia.org/wiki/RSVP_(skr%C3%B3towiec]RSVP[/url].
Twórz zdarzenia i zadania oraz zarządzaj nimi, które mogą być również chronione za pomocą list kontroli dostępu. Wydarzenia można importować i eksportować do innego oprogramowania przy użyciu standardowego formatu vcalendar lub iCal i udostępniać w wpisuch innym osobom. Wydarzenia urodzinowe automatycznie dodawane od znajomych i konwertowane na właściwą strefę czasową, dzięki czemu będziesz dokładnie wiedzieć, kiedy mają miejsce urodziny - bez względu na to, gdzie się znajdujesz na świecie w stosunku do osoby urodzonej w dniu urodzin. Wydarzenia zwykle tworzone za pomocą liczników obecności, dzięki czemu Twoi znajomi i kontakty mogą natychmiast [url=https://pl.wikipedia.org/wiki/RSVP_(skr%C3%B3towiec]RSVP[/url].
[h4]Czaty[/h4]
Możesz utworzyć dowolną liczbę osobistych czatów i zezwolić na dostęp za pośrednictwem list kontroli dostępu. one zazwyczaj bezpieczniejsze niż XMPP, IRC i inne rodzaje przesyłania wiadomości błyskawicznych, chociaż zezwalamy również na korzystanie z tych innych usług za pośrednictwem wtyczek.
@@ -82,7 +93,7 @@ Udostępniaj i zapisuj albo zarządzaj zakładkami z linków podanych na czacie.
[h4]Szyfrowanie wiadomości prywatnych i kwestie prywatności[/h4]
Prywatna poczta jest przechowywana w ukrytym formacie. Chociaż nie jest to "kuloodporne", zwykle zapobiega przypadkowemu podsłuchiwaniu przez administratora witryny lub usługodawcę internetowego.
Każdy kanał serwisu $Projectname ma swój własny unikalny zestaw prywatnych i powiązanych publicznych kluczy RSA 4096-bitowych, generowanych podczas pierwszego tworzenia kanałów. Służy do ochrony przesyłanych prywatnych wiadomości i postów.
Każdy kanał serwisu $Projectname ma swój własny unikalny zestaw prywatnych i powiązanych publicznych kluczy RSA 4096-bitowych, generowanych podczas pierwszego tworzenia kanałów. Służy do ochrony przesyłanych prywatnych wiadomości i wpisów.
Ponadto wiadomości mogą być tworzone przy użyciu "szyfrowania end-to-end", którego nie mogą odczytać operatorzy serwisów $Projectname, dostawcy usług internetowych ani nikt, kto nie zna hasła.
@@ -90,24 +101,24 @@ Wiadomości publiczne na ogół nie są szyfrowane podczas przesyłania ani prze
Prywatne wiadomości mogą zostać wycofane po wysłaniu, chociaż nie ma gwarancji, że odbiorca ich jeszcze nie przeczytał.
Posty i wiadomości mogą być tworzone z datą wygaśnięcia, po którym zostaną usunięte lub usunięte ze strony odbiorcy.
Wpisy i wiadomości mogą być tworzone z datą wygaśnięcia, po którym zostaną usunięte lub usunięte ze strony odbiorcy.
[h4]Federalizacja usług (Service Federation)[/h4]
Oprócz dodatkowych "łączników cross-post" do różnych alternatywnych sieci, istnieje natywna obsługa importu treści z kanałów RSS i Atom i wykorzystywania jej do tworzenia specjalnych kanałów. Dostępne również wtyczki do komunikacji z innymi sieciami za pomocą protokołów Diaspora i GNU-Social (OStatus). Sieci te nie obsługują tożsamości nomadycznej ani kontroli dostępu między domenami. Jednak podstawowa komunikacja jest obsługiwana: do i z Diaspora, Friendica, GNU-Social, Mastodon i innych dostawców, którzy używają tych protokołów.
Oprócz dodatkowych łączników między wpisami z różnych alternatywnych sieci, istnieje natywna obsługa importu treści z kanałów RSS i Atom i wykorzystywania jej do tworzenia specjalnych kanałów. Dostępne również wtyczki do komunikacji z innymi sieciami za pomocą protokołów Diaspora i GNU-Social (OStatus). Sieci te nie obsługują tożsamości nomadycznej ani kontroli dostępu między domenami. Jednak podstawowa komunikacja jest obsługiwana: do i z Diaspora, Friendica, GNU-Social, Mastodon i innych dostawców, którzy używają tych protokołów.
Istnieje również eksperymentalna obsługa uwierzytelniania OpenID, której można używać na listach kontroli dostępu. To jest jeszcze w trakcie tworzenia, ale poeksperymentować można. Twój hub $Projectname może być używany jako dostawca OpenID do uwierzytelniania członków w zewnętrznych usługach korzystających z tej technologii.
Istnieje również eksperymentalna obsługa uwierzytelniania OpenID, której można używać na listach kontroli dostępu. To jest jeszcze w trakcie tworzenia, ale poeksperymentować można. Twój węzeł $Projectname może być używany jako dostawca OpenID do uwierzytelniania członków w zewnętrznych usługach korzystających z tej technologii.
Kanały mogą mieć uprawnienia, aby stać się "kanałami pochodnymi", w przypadku gdy dwa lub więcej istniejących kanałów łączy się, tworząc nowy kanał tematyczny.
[h4]Grupy prywatności (Privacy Group)[/h4]
Nasza implementacja grup prywatności jest podobna do "kręgów" w Google i "aspektów" w Diasporze. Pozwala to na filtrowanie przychodzącego strumienia według wybranych grup i automatyczne ustawianie wychodzącej listy kontroli dostępu tylko na te z tej grupy prywatności podczas publikowania. Możesz to zmienić w dowolnym momencie (przed wysłaniem postu).
Nasza implementacja grup prywatności jest podobna do "kręgów" w Google i "aspektów" w Diasporze. Pozwala to na filtrowanie przychodzącego strumienia według wybranych grup i automatyczne ustawianie wychodzącej listy kontroli dostępu tylko na te z tej grupy prywatności podczas publikowania. Możesz to zmienić w dowolnym momencie (przed wysłaniem wpisu).
[h4]Usługi katalogowe (Directory Services)[/h4]
Zapewniamy łatwy dostęp do katalogu członków i udostępniamy zdecentralizowane narzędzia, które mogą dostarczać "sugestie" znajomych. Katalogi to zwykłe serwisy $Projectname, które zdecydowały się zaakceptować rolę serwera katalogowego. Wymaga to więcej zasobów niż większość typowych serwisów, więc nie jest to ustawienie domyślne. Katalogi synchronizowane i dublowane, dzięki czemu wszystkie zawierają aktualne informacje o całej sieci (z zastrzeżeniem normalnych opóźnień propagacji).
Zapewniamy łatwy dostęp do katalogu członków i udostępniamy zdecentralizowane narzędzia, które mogą dostarczać "sugestie" znajomych. Katalogi to zwykłe serwisy $Projectname, które zdecydowały się zaakceptować rolę serwera katalogowego. Wymaga to więcej zasobów niż większość typowych serwisów, więc nie jest to ustawienie domyślne. Katalogi synchronizowane i dublowane, dzięki czemu wszystkie zawierają aktualne informacje o całej sieci (z zastrzeżeniem normalnych opóźnień propagacji). Więcej na ten temat znajdziesz w artykule [Konfiguracja katalogu](/help/pl/directories).
[h4]TLS/SSL[/h4]
W przypadku hubów $Projectname, które używają TLS/SSL, komunikacja między klientem a serwerem jest szyfrowana za pomocą protokołu TLS/SSL. Biorąc pod uwagę niedawno ujawnione w mediach fakty dotyczące powszechnego, globalnego nadzoru i obchodzenia szyfrowania przez NSA i GCHQ, uzasadnione jest założenie, że komunikacja chroniona przez HTTPS może być zagrożona na różne sposoby. W konsekwencji prywatna komunikacja jest szyfrowana na wyższym poziomie przed wysłaniem na zewnątrz.
W przypadku węzłów $Projectname, które używają TLS/SSL, komunikacja między klientem a serwerem jest szyfrowana za pomocą protokołu TLS/SSL. Biorąc pod uwagę niedawno ujawnione w mediach fakty dotyczące powszechnego, globalnego nadzoru i obchodzenia szyfrowania przez NSA i GCHQ, uzasadnione jest założenie, że komunikacja chroniona przez HTTPS może być zagrożona na różne sposoby. W konsekwencji prywatna komunikacja jest szyfrowana na wyższym poziomie przed wysłaniem na zewnątrz.
[h4]Konfiguracja kanałów[/h4]
Podczas tworzenia kanału wybierana jest rola, która stosuje szereg wstępnie skonfigurowanych ustawień zabezpieczeń i prywatności. one wybierane z uwzględnieniem najlepszych praktyk, aby zachować prywatność na żądanym poziomie.
@@ -124,27 +135,27 @@ W przypadku wybrania "własnej" roli prywatności każdy kanał umożliwia precy
[h4]Prywatne i publiczne fora[/h4]
Fora to zazwyczaj kanały, w których może uczestniczyć wielu autorów. Obecnie istnieją dwa mechanizmy publikowania postów na forach:
Fora to zazwyczaj kanały, w których może uczestniczyć wielu autorów. Obecnie istnieją dwa mechanizmy publikowania wpisów na forach:
- posty "wall-to-wall" i
- wpisy na całą ścianę (ang. wall-to-wall) i
- mechanizm tagów forowych @mention.
Fora mogą być tworzone przez każdego i używane w dowolnym celu. Katalog zawiera opcję wyszukiwania forów publicznych. Fora prywatne mogą być publikowane tylko dla członków i często tylko przez nich widoczne.
[h4]Klonowanie kont[/h4]
Konta platformy $Projectname nazywane *tożsamościami nomadycznymi*, ponieważ tożsamość członka nie jest powiązana z hubem, w którym tożsamość została pierwotnie utworzona. Na przykład, kiedy tworzysz konto na Facebooku lub Gmailu, jest ono powiązane z tymi usługami - mie może dział poza Facebook.com czy Gmail.com.
[h4]Klonowanie tożsamości[/h4]
Kanały platformy $Projectname nazywane [i]tożsamościami nomadycznymi[/i], ponieważ tożsamość członka (jego profil i związany z nim kanał) nie jest powiązana z węzłem, w którym tożsamość została pierwotnie utworzona. Na przykład, kiedy tworzysz konto na Facebooku lub Gmailu, jest ono ściśle powiązane z tymi usługami - mie możesz używ tych usług poza Facebook.com czy Gmail.com. Z drugiej strony załóżmy, że masz konto na serwisie Hubzillahub.com i w ramach tego konta utworzyłeś kanał o nazwie [code]jacek@Hubzillahub.com[/code]. Możesz sklonować go do innego węzła Hubzilla, wybierając samą lub inną nazwę, np. [code]blogJacka@SomeHubzillahub.info[/code].
Z drugiej strony załóżmy, że utworzyłeś tożsamość $Projectname o nazwie [code]tina@$Projectnamehub.com[/code]. Możesz sklonować do innego huba $Projectname, wybierając samą lub inną nazwę, np. [code]liveForever@Some$ProjectnameHub.info[/code].
Z drugiej strony załóżmy, że utworzyłeś tożsamość $Projectname o nazwie [code]tina@$Projectnamehub.com[/code]. Możesz sklonować do innego węzła $Projectname, wybierając samą lub inną nazwę, np. [code]liveForever@Some$ProjectnameHub.info[/code].
Oba kanały teraz zsynchronizowane, co oznacza, że wszystkie Twoje kontakty i preferencje zostaną zduplikowane na klonie. Nie ma znaczenia, czy wyślesz post z pierwotnego centrum, czy z nowego. Posty będą dublowane na obu kontach.
Oba kanały teraz zsynchronizowane, co oznacza, że wszystkie Twoje kontakty i preferencje zostaną zduplikowane na klonie. Nie ma znaczenia, czy wyślesz wpis z pierwotnego centrum, czy z nowego. Wpisy będą dublowane na obu kontach.
To dość rewolucyjna funkcja, jeśli weźmiemy pod uwagę kilka scenariuszy:
- Co się stanie, jeśli hub, w którym oparta jest tożsamość, nagle przestanie działać? Bez sklonowania tożsamości członek tego huba nie będzie mógł się komunikować, dopóki hub nie wróci do trybu online (bez wątpienia wielu z Was widziało i przeklęło "Fail Whale" na Twitterze). Dzięki klonowaniu wystarczy zalogować się na sklonowane konto, a życie toczy się normalnie.
- Co się stanie, jeśli węzeł, na którym oparta jest tożsamość, nagle przestanie działać? Bez sklonowania tożsamości członek tego węzła nie będzie mógł się komunikować, dopóki węzeł nie wróci do trybu online (bez wątpienia wielu z Was widziało i przeklęło "Fail Whale" na Twitterze). Dzięki klonowaniu wystarczy zalogować się na sklonowane konto, a życie toczy się normalnie.
- Administrator twojego huba nie może już sobie pozwolić na opłacanie swojego bezpłatnego i publicznego huba $Projectname. Zapowiada, że hub zostanie zamknięty za dwa tygodnie. Dzięki temu masz wystarczająco dużo czasu na sklonowanie swojej tożsamośc i zachowanie relacji, znajomych i treści z zamykanego serwisu $Projectname.
- Administrator twojego węzła nie może już sobie pozwolić na opłacanie swojego bezpłatnego i publicznego węzła $Projectname. Zapowiada, że węzeł zostanie zamknięty za dwa tygodnie. Dzięki temu masz wystarczająco dużo czasu na sklonowanie swojej tożsamośc i zachowanie relacji, znajomych i treści z zamykanego serwisu $Projectname.
- A jeśli Twoja tożsamość podlega rządowej cenzurze? Twój dostawca huba może zostać zmuszony do usunięcia Twojego konta wraz z wszelkimi tożsamościami i powiązanymi danymi. Dzięki klonowaniu, $Projectname stawia opór cenzurze. Możesz mieć setki klonów, jeśli chcesz, wszystkie nazwane inaczej i istniejące w wielu różnych hubach, rozrzuconych po Internecie.
- A jeśli Twoja tożsamość podlega rządowej cenzurze? Twój dostawca węzła może zostać zmuszony do usunięcia Twojego konta wraz z wszelkimi tożsamościami i powiązanymi danymi. Dzięki klonowaniu, $Projectname stawia opór cenzurze. Możesz mieć setki klonów, jeśli chcesz, wszystkie nazwane inaczej i istniejące w wielu różnych węzłach, rozrzuconych po Internecie.
$Projectname oferuje interesujące nowe możliwości prywatności. Więcej informacji można znaleźć na stronie "Najlepsze praktyki w komunikacji prywatnej".
Obowiązują pewne zastrzeżenia. Aby uzyskać pełne wyjaśnienie klonowania tożsamości, przeczytaj stronę "JAK SKLONOWAĆ SWOJĄ TOŻSAMOŚĆ".
@@ -157,19 +168,19 @@ Można utworzyć dowolną liczbę profili zawierających różne informacje, kt
$Projectname oferuje prosty sposób wykonywania kopii zapasowej konta za jednym kliknięciem, z której możesz pobrać pełną kopię zapasową swoich profili. Kopie zapasowe można następnie wykorzystać do sklonowania lub przywrócenia profilu.
[h4]Usuwanie konta[/h4]
Konta można natychmiast usunąć, klikając link. Otóż to. Wszystkie powiązane treści następnie usuwane z siatki (w tym posty i wszelkie inne treści utworzone przez usunięty profil). W zależności od liczby posiadanych połączeń proces usuwania zdalnej zawartości może zająć trochę czasu, ale zaplanowany jest tak szybko, jak to możliwe.
Konta można natychmiast usunąć, klikając link. Otóż to. Wszystkie powiązane treści następnie usuwane z sieci (w tym wpisy i wszelkie inne treści utworzone przez usunięty profil). W zależności od liczby posiadanych połączeń proces usuwania zdalnej zawartości może zająć trochę czasu, ale zaplanowany jest tak szybko, jak to możliwe.
[h4]Usuwanie treści[/h4]
Wszelkie treści utworzone w Hubzilli pozostają pod kontrolą członka (lub kanału), który je pierwotnie utworzył. W dowolnym momencie członek może usunąć wiadomość lub zakres wiadomości. Proces usuwania zapewnia, że treść zostanie usunięta, niezależnie od tego, czy została opublikowana w głównym (macierzystym) hubie kanału, czy w innym hubie, gdzie kanał został zdalnie uwierzytelniony za pośrednictwem Zot (protokół komunikacji i uwierzytelniania $Projectname).
Wszelkie treści utworzone w Hubzilli pozostają pod kontrolą członka (lub kanału), który je pierwotnie utworzył. W dowolnym momencie członek może usunąć wiadomość lub zakres wiadomości. Proces usuwania zapewnia, że treść zostanie usunięta, niezależnie od tego, czy została opublikowana w głównym (macierzystym) węźle kanału, czy w innym węźle, gdzie kanał został zdalnie uwierzytelniony za pośrednictwem Zot (protokół komunikacji i uwierzytelniania $Projectname).
[h4]Media[/h4]
Podobnie jak każdy inny nowoczesny system blogowania, sieć społecznościowa lub usługa mikroblogowania, $Projectname obsługuje przesyłanie plików, osadzanie filmów, łączenie stron internetowych.
[h4]Podgląd i edycja[/h4]
Posty i komentarze można przeglądać przed wysłaniem i edytować po wysłaniu.
Wpisy i komentarze można przeglądać przed wysłaniem i edytować po wysłaniu.
[h4]Głosowanie i konsensus[/h4]
Posty mogą być przekształcane w elementy "konsensusu", które pozwalają czytelnikom oferować opinie, które zestawiane w liczniki "zgadzam się", "nie zgadzam się" i "wstrzymuję się". Pozwala to ocenić zainteresowanie pomysłami i tworzyć nieformalne ankiety.
Wpisy mogą być przekształcane w elementy "konsensusu", które pozwalają czytelnikom oferować opinie, które zestawiane w liczniki "zgadzam się", "nie zgadzam się" i "wstrzymuję się". Pozwala to ocenić zainteresowanie pomysłami i tworzyć nieformalne ankiety.
[h4]Rozszerzaie $Projectname[/h4]

View File

@@ -1,9 +1,8 @@
[h3]Zarządzanie projektem $Projectname[/h3]
Zarządzanie $Projectname odnosi się do zarządzania tym projektem i zwłaszcza jak do rozwiązywania konfliktów w tym projekcie.
Zarządzanie $Projectname odnosi się do zarządzania tym projektem a zwłaszcza do tego jak rozwiązywane konflikty w tym projekcie.
[h4]Zarządzanie społecznością[/h4]
Projekt jest utrzymywany przez społeczność $Projectname i decyzje podejmowane w ramach tej społeczności.
Struktura zarządzania ciągle ewoluuje. Do czasu zakończenia tworzenia struktura, decyzje podejmowane w następującej kolejności:
Projekt jest utrzymywany przez społeczność $Projectname i decyzje podejmowane w ramach tej społeczności. Struktura zarządzania ciągle się rozwija. Do czasu zakończenia tworzenia tej struktury, decyzje podejmowane w następującej kolejności:
[ol]
[*] Opóźniony konsensus
@@ -13,7 +12,7 @@ Jeśli propozycja projektu zostanie złożona na jednym z forów zarządzania pr
[*] Weto
Starsi deweloperzy, z długim stażem w projekcie. mogą zawetować każdą decyzję. Decyzja może zostać podjęta dopiero po usunięciu weta lub przedłożeniu alternatywnej propozycji.
Starsi deweloperzy, z długim stażem w projekcie, mogą zawetować każdą decyzję. Decyzja może zostać podjęta dopiero po usunięciu weta lub przedłożeniu alternatywnej propozycji.
[*] Głosowanie społeczności
@@ -27,25 +26,25 @@ Głosowanie społeczności nie zawsze zapewnia Powszechnie akceptowany wynik i m
Q: Kto może widzieć moją treść?
A: Domyślnie KAŻDY w internecie, chyba że ograniczysz do niej dostęp. $Projectname pozwala wybrać żądany poziom prywatności. Treści podlegające ograniczeniom NIE będą widoczne dla "sieci szpiegowskich" i reklamodawców. Będą chroniona przed podsłuchem przez osoby postronne - najlepiej jak potrafimy. Administratorzy centrów z wystarczającymi umiejętnościami i cierpliwością MOGĄ być w stanie podsłuchiwać niektóre prywatne wiadomości, ale muszą dołożyć starań, aby to zrobić. W $Projectname istnieją tryby prywatności, które nawet odporne na podsłuchiwanie przez wykwalifikowanych i zdeterminowanych administratorów hubów.
A: Domyślnie KAŻDY w Internecie, chyba że ograniczysz do niej dostęp. $Projectname pozwala wybrać żądany poziom prywatności. Treści podlegające ograniczeniom NIE będą widoczne dla "sieci szpiegowskich" i reklamodawców. Będą chroniona przed podsłuchem przez osoby wpisronne - najlepiej jak potrafimy. Administratorzy centrów z wystarczającymi umiejętnościami i cierpliwością MOGĄ być w stanie podsłuchiwać niektóre prywatne wiadomości, ale muszą dołożyć starań, aby to zrobić. W $Projectname istnieją tryby prywatności, które nawet odporne na podsłuchiwanie przez wykwalifikowanych i zdeterminowanych administratorów węzłów.
Q: Czy moje treści mogą zostać ocenzurowane?
A: Z założenie, $Projectname (jako sieć) NIE MOŻE cenzurować twoich treści. Administratorzy serwerów i hubów podlegają lokalnemu prawodawstwu i MOGĄ usunąć budzące zastrzeżenia treści ze swojego serwisu (huba). Każdy może zostać administratorem huba, w tym Ty. Dlatego publikuj treści, które w innym przypadku mogłyby zostać ocenzurowane. Nadal MOŻESZ podlegać lokalnemu prawodawstwu.
A: Z założenie, $Projectname (jako sieć) NIE MOŻE cenzurować twoich treści. Administratorzy serwerów i węzłów podlegają lokalnemu prawodawstwu i MOGĄ usunąć budzące zastrzeżenia treści ze swojego serwisu (węzła). Każdy może zostać administratorem węzła, w tym Ty. Dlatego publikuj treści, które w innym przypadku mogłyby zostać ocenzurowane. Nadal MOŻESZ podlegać lokalnemu prawodawstwu.
[h5]Definicje[/h5]
**$Projectname**
Inaczej nazywana "siecią", $Projectname jest zbiorem pojedynczych komputerów (serwerów) (czyli **hubów**. ang. *hubs*), które łączą się razem, tworząc większą sieć kooperacyjną.
Inaczej nazywana "siecią", $Projectname jest zbiorem pojedynczych komputerów (serwerów) (czyli **węzłów**. ang. *hubs*), które łączą się razem, tworząc większą sieć kooperacyjną.
**hub** (ang. *hub*)
**węzeł** (ang. *hub*)
Pojedynczy komputer lub serwer podłączony do $Projectname. Jest on dostarczany przez **administratora huba** i może być publiczny lub prywatny, płatnu lub bezpłatny.
Pojedynczy komputer lub serwer podłączony do $Projectname. Jest on dostarczany przez **administratora węzła** i może być publiczny lub prywatny, płatnu lub bezpłatny.
*administrator huba**
*administrator węzła**
Operator systemu pojedynczego huba.
Operator systemu pojedynczego węzła.
[h5]Polityki[/h5]
@@ -55,41 +54,41 @@ Wszelkie informacje lub cokolwiek zamieszczone przez Ciebie w $Projectname MOŻE
Twoje zdjęcie profilowe, nazwa Twojego kanału i lokalizacja (adres URL lub adres sieciowy) Twojego kanału widoczne dla każdego w internecie, a kontrola prywatności nie wpływa na wyświetlanie tych elementów.
MOŻESZ dodatkowo podać inne informacje profilowe. Wszelkie informacje, które podajesz w swoim domyślnym lub **publicznym profilu** MOGĄ zostać przesłane do innych hubów w $Projectname i dodatkowo MOGĄ zostać wyświetlone w katalogu kanałów. Możesz ograniczyć wyświetlanie tych informacji profilowych. Może być ograniczone tylko do członków twojego huba lub tylko połączeń (znajomych) lub innych ograniczonych grup widzów, zgodnie z twoim życzeniem. Jeśli chcesz, aby Twój profil był ograniczony, musisz ustawić odpowiednie ustawienia prywatności lub po prostu NIE podawać dodatkowych informacji.
MOŻESZ dodatkowo podać inne informacje profilowe. Wszelkie informacje, które podajesz w swoim domyślnym lub **publicznym profilu** MOGĄ zostać przesłane do innych węzłów w $Projectname i dodatkowo MOGĄ zostać wyświetlone w katalogu kanałów. Możesz ograniczyć wyświetlanie tych informacji profilowych. Może być ograniczone tylko do członków twojego węzła lub tylko połączeń (znajomych) lub innych ograniczonych grup widzów, zgodnie z twoim życzeniem. Jeśli chcesz, aby Twój profil był ograniczony, musisz ustawić odpowiednie ustawienia prywatności lub po prostu NIE podawać dodatkowych informacji.
**Treść**
Treści, które udostępniasz (posty ze statusami, zdjęcia, pliki itp.) Należą do Ciebie. $Projectname domyślnie publikuje treści w sposób otwarty i widoczny dla każdego w internecie (PUBLICZNY). MOŻESZ kontrolować to w ustawieniach swojego kanału i ograniczyć domyślne uprawnienia lub MOŻESZ ograniczyć widoczność każdego pojedynczego opublikowanego elementu oddzielnie (PRYWATNE). Programiści $Projectname zapewnią, że ograniczone treści będą widoczne TYLKO dla osób z listy ograniczeń - najlepiej jak potrafią.
Treści, które udostępniasz (wpisy ze statusami, zdjęcia, pliki itp.) Należą do Ciebie. $Projectname domyślnie publikuje treści w sposób otwarty i widoczny dla każdego w internecie (PUBLICZNY). MOŻESZ kontrolować to w ustawieniach swojego kanału i ograniczyć domyślne uprawnienia lub MOŻESZ ograniczyć widoczność każdego pojedynczego opublikowanego elementu oddzielnie (PRYWATNE). Programiści $Projectname zapewnią, że ograniczone treści będą widoczne TYLKO dla osób z listy ograniczeń - najlepiej jak potrafią.
Treści (zwłaszcza posty statusowe), które udostępniasz innym sieciom lub które udostępniłeś komukolwiek w Internecie (PUBLICZNE), nie mogą być łatwo cofnięte po ich opublikowaniu. MOGĄ być udostępniane innym sieciom i udostępniane za pośrednictwem kanałów RSS / Atom. Może być również rozpowszechniany na innych stronach $ Projectname. MOŻE pojawiać się w innych sieciach i witrynach internetowych oraz być widoczny w wyszukiwarkach internetowych. Jeśli nie chcesz tego domyślnego zachowania, dostosuj ustawienia swojego kanału i ogranicz listę osób, które mogą oglądać Twoje treści.
Treści (zwłaszcza wpisy statusowe), które udostępniasz innym sieciom lub które udostępniłeś komukolwiek w Internecie (PUBLICZNE), nie mogą być łatwo cofnięte po ich opublikowaniu. MOGĄ być udostępniane innym sieciom i udostępniane za pośrednictwem kanałów RSS / Atom. Może być również rozpowszechniany na innych stronach $ Projectname. MOŻE pojawiać się w innych sieciach i witrynach internetowych oraz być widoczny w wyszukiwarkach internetowych. Jeśli nie chcesz tego domyślnego zachowania, dostosuj ustawienia swojego kanału i ogranicz listę osób, które mogą oglądać Twoje treści.
**Komentarze i wpisy na forach**
Komentarze do postów stworzonych przez innych oraz posty oznaczone jako posty na forum należą do Ciebie jako twórcy (autora), ale ich dystrybucja nie jest pod Twoją bezpośrednią kontrolą i zrzekasz się NIEKTÓRYCH praw do tych elementów. Te posty i komentarze MOGĄ być ponownie rozpowszechniane wśród innych i MOGĄ być widoczne dla każdego w internecie. W przypadku komentarzy, twórca "pierwszej wiadomości" w wątku (rozmowie), na który odpowiadasz, kontroluje dystrybucję wszystkich komentarzy i odpowiedzi na wiadomość. Jest on "właścicielem" i dlatego ma określone prawa w odniesieniu do całej rozmowy (w tym wszystkich zawartych w niej komentarzy). Nadal możesz edytować lub usuwać komentarz, ale właściciel konwersacji ma również prawa do edytowania, usuwania, ponownej dystrybucji i tworzenia kopii zapasowych i przywracania dowolnej lub całej zawartości konwersacji.
Komentarze do wpisów stworzonych przez innych oraz wpisy oznaczone jako wpisy na forum należą do Ciebie jako twórcy (autora), ale ich dystrybucja nie jest pod Twoją bezpośrednią kontrolą i zrzekasz się NIEKTÓRYCH praw do tych elementów. Te wpisy i komentarze MOGĄ być ponownie rozpowszechniane wśród innych i MOGĄ być widoczne dla każdego w internecie. W przypadku komentarzy, twórca "pierwszej wiadomości" w wątku (rozmowy), na który odpowiadasz, kontroluje dystrybucję wszystkich komentarzy i odpowiedzi na wiadomość. Jest on "właścicielem" i dlatego ma określone prawa w odniesieniu do całej rozmowy (w tym wszystkich zawartych w niej komentarzy). Nadal możesz edytować lub usuwać komentarz, ale właściciel rozmowy ma również prawa do edytowania, usuwania, ponownej dystrybucji i tworzenia kopii zapasowych i przywracania dowolnej lub całej zawartości rozmowy.
**Informacja prywatna**
Programiści $Projectname zapewnią, że każda dostarczona przez Ciebie zawartość oznaczona jako PRYWATNA będzie chroniona przed podsłuchem - najlepiej jak potrafią. Zawartość kanału prywatnego MOŻE być widoczna w bazie danych każdego zaangażowanego administratora centrum, ale prywatne wiadomości ukrywane w bazie danych. To ostatnie oznacza, że jest to bardzo trudne, ale NIE niemożliwe, aby te treści były widoczne dla administratora centrum. Treść kanału prywatnego i wiadomości prywatne również usuwane z powiadomień e-mail. Pełne szyfrowanie jest oferowane jako funkcja opcjonalna i NIE MOŻE być widoczne, nawet dla zdeterminowanego administratora.
Programiści $Projectname zapewnią, że każda dostarczona przez Ciebie zawartość oznaczona jako PRYWATNA będzie chroniona przed podsłuchem - najlepiej jak potrafią. Zawartość kanału prywatnego MOŻE być widoczna w bazie danych każdego zaangażowanego administratora węzła, ale prywatne wiadomości ukrywane w bazie danych. To ostatnie oznacza, że jest to bardzo trudne, ale NIE niemożliwe, aby te treści były widoczne dla administratora węzła. Treść kanału prywatnego i wiadomości prywatne również usuwane z powiadomień e-mail. Pełne szyfrowanie jest oferowane jako funkcja opcjonalna i NIE MOŻE być widoczne, nawet dla zdeterminowanego administratora.
[h5]Prywatność tożsamości[/h5]
Prywatność dla Twojej tożsamości to kolejny aspekt. Ponieważ masz zdecentralizowaną tożsamość w $Projectname, Twoja prywatność wykracza poza domowy hub. Jeśli chcesz mieć pełną kontrolę nad swoją prywatnością i bezpieczeństwem, powinieneś uruchomić własny hub na dedykowanym serwerze. Dla wielu osób jest to skomplikowane ale może poszerzyć ich możliwości techniczne. Wymieńmy więc kilka środków ostrożności, które możesz podjąć, aby zapewnić sobie jak największą prywatność.
Prywatność dla Twojej tożsamości to kolejny aspekt. Ponieważ masz zdecentralizowaną tożsamość w $Projectname, Twoja prywatność wykracza poza domowy węzeł. Jeśli chcesz mieć pełną kontrolę nad swoją prywatnością i bezpieczeństwem, powinieneś uruchomić własny węzeł na dedykowanym serwerze. Dla wielu osób jest to skomplikowane ale może poszerzyć ich możliwości techniczne. Wymieńmy więc kilka środków ostrożności, które możesz podjąć, aby zapewnić sobie jak największą prywatność.
Zdecentralizowana tożsamość ma wiele zalet i daje wiele interesujących funkcji, ale powinieneś być świadomy faktu, że Twoja tożsamość jest znana innym hubom w sieci $Projectname. Jedną z tych zalet jest to, że inne kanały mogą udostępniać dostosowane treści i umożliwiać oglądanie prywatnych rzeczy (takich jak prywatne zdjęcia, które inni chcą Ci udostępnić). Z tego powodu te kanały muszą wiedzieć, kim jesteś. Ale rozumiemy, że czasami te inne kanały wiedzą od Ciebie więcej, niż byś sobie tego życzył. Na przykład wtyczka Visage, która może poinformować właściciela kanału o ostatniej wizycie w jego profilu. Możesz łatwo zrezygnować z tego niskiego poziomu i uważamy, że jest to nieszkodliwe śledzenie.
Zdecentralizowana tożsamość ma wiele zalet i daje wiele interesujących funkcji, ale powinieneś być świadomy faktu, że Twoja tożsamość jest znana innym węzłom w sieci $Projectname. Jedną z tych zalet jest to, że inne kanały mogą udostępniać dostosowane treści i umożliwiać oglądanie prywatnych rzeczy (takich jak prywatne zdjęcia, które inni chcą Ci udostępnić). Z tego powodu te kanały muszą wiedzieć, kim jesteś. Ale rozumiemy, że czasami te inne kanały wiedzą od Ciebie więcej, niż byś sobie tego życzył. Na przykład wtyczka Visage, która może poinformować właściciela kanału o ostatniej wizycie w jego profilu. Możesz łatwo zrezygnować z tego niskiego poziomu i uważamy, że jest to nieszkodliwe śledzenie.
* Możesz włączyć [Do Not Track (DNT)](http://donottrack.us/) w swojej przeglądarce internetowej. Szanujemy nową propozycję polityki prywatności. Wszystkie nowoczesne przeglądarki obsługują DNT. Znajdziesz to w ustawieniach prywatności swojej przeglądarki lub możesz zapoznać się z instrukcją przeglądarki internetowej. Nie wpłynie to na funkcjonalność $Projectname. To ustawienie jest prawdopodobnie wystarczające dla większości ludzi.
* Możesz włączyć [url=http://donottrack.us/]Do Not Track (DNT)[/url] w swojej przeglądarce internetowej. Szanujemy nową propozycję polityki prywatności. Wszystkie nowoczesne przeglądarki obsługują DNT. Znajdziesz to w ustawieniach prywatności swojej przeglądarki lub możesz zapoznać się z instrukcją przeglądarki internetowej. Nie wpłynie to na funkcjonalność $Projectname. To ustawienie jest prawdopodobnie wystarczające dla większości ludzi.
* Możesz [wyłączyć publikację](ustawienia) swojego kanału w naszym katalogu kanałów. Jeśli chcesz, aby ludzie mogli znaleźć Twój kanał, podaj im adres swojego kanału. Uważamy, że jest to dobra wskazówka, że wolisz dodatkową prywatność i automatycznie włączasz opcję "Nie śledź", jeśli tak jest.
* Możesz [url=[baseurl]/settings]wyłączyć publikację[/url] swojego kanału w naszym katalogu kanałów. Jeśli chcesz, aby ludzie mogli znaleźć Twój kanał, podaj im adres swojego kanału. Uważamy, że jest to dobra wskazówka, że wolisz dodatkową prywatność i automatycznie włączasz opcję "Nie śledź", jeśli tak jest.
* Możesz mieć zablokowany hub. Oznacza to, że wszystkie kanały i treści w tym centrum nie publiczne ani widoczne dla świata zewnętrznego. To jest coś, co może zrobić tylko administrator centrum. Szanujemy to również i automatycznie włączamy opcję "Nie śledź:, jeśli jest ustawiona.
* Możesz mieć zablokowany węzeł. Oznacza to, że wszystkie kanały i treści w tym wężle nie publiczne ani widoczne dla świata zewnętrznego. To jest coś, co może zrobić tylko administrator węzła. Szanujemy to również i automatycznie włączamy opcję "Nie śledź:, jeśli jest ustawiona.
[h5]Cenzura[/h5]
$Projectname to globalna sieć obejmująca wszystkie religie i kultury. Nie oznacza to, że każdy członek sieci czuje się tak samo jak Ty w spornych kwestiach, a niektórzy ludzie mogą MOCNO sprzeciwić się publikowanym przez Ciebie treściom. Ogólnie rzecz biorąc, jeśli chcesz opublikować coś, o czym wiesz, że nie jest powszechnie akceptowane, najlepszym rozwiązaniem jest ograniczenie odbiorców za pomocą kontroli prywatności do małego kręgu znajomych.
$Projectname jako dostawca sieci nie może cenzurować zawartości. Jednak administratorzy hubów MOGĄ cenzurować wszelkie treści, które pojawiają się w ich hubie, aby zachować zgodność z lokalnym prawem, a nawet osobistym osądem. Ich decyzja jest ostateczna. Jeśli masz problemy z jakimkolwiek administratorem huba, możesz przenieść swoje konto i wpisy do innej witryny, która jest bardziej zgodna z Twoimi oczekiwaniami. Sprawdzaj (okresowo) [Warunki świadczenia usług](help/TermsOfService) swojego huba, aby poznać wszelkie zasady lub wytyczne. Jeśli Twoje treści składają się z materiałów, które są nielegalne lub mogą powodować problemy, MOCNO zachęcamy do hostowania własnych (zostań administratorem własnego huba). Mimo to. możesz stwierdzić, że Twoje treści są zablokowane w niektórych hubach, ale $Projectname jako sieć nie może wogóle zablokować ich publikowania.
$Projectname jako dostawca sieci nie może cenzurować zawartości. Jednak administratorzy węzłów MOGĄ cenzurować wszelkie treści, które pojawiają się w ich węźle, aby zachować zgodność z lokalnym prawem, a nawet osobistym osądem. Ich decyzja jest ostateczna. Jeśli masz problemy z jakimkolwiek administratorem węzła, możesz przenieść swoje konto i wpisy do innej witryny, która jest bardziej zgodna z Twoimi oczekiwaniami. Sprawdzaj (okresowo) [Warunki świadczenia usług](help/TermsOfService) swojego węzła, aby poznać wszelkie zasady lub wytyczne. Jeśli Twoje treści składają się z materiałów, które są nielegalne lub mogą powodować problemy, MOCNO zachęcamy do hostowania własnych (zostań administratorem własnego węzła). Mimo to. możesz stwierdzić, że Twoje treści są zablokowane w niektórych węzłach, ale $Projectname jako sieć nie może wogóle zablokować ich publikowania.
$Projectname ZALECA, aby administratorzy hubów zapewnili okres karencji wynoszący 1-2 dni między ostrzeżeniem właściciela konta o treści, którą należy usunąć, a fizycznym usunięciem lub wyłączeniem konta. Dzięki temu właściciel treści będzie mógł wyeksportować metadane swojego kanału i zaimportować je do innej witryny. W rzadkich przypadkach treść może mieć taki charakter, że uzasadnia natychmiastowe zamknięcie konta. To jest decyzja właściciela huba, a nie decyzja $Projectname.
$Projectname ZALECA, aby administratorzy węzłów zapewnili okres karencji wynoszący 1-2 dni między ostrzeżeniem właściciela konta o treści, którą należy usunąć, a fizycznym usunięciem lub wyłączeniem konta. Dzięki temu właściciel treści będzie mógł wyeksportować metadane swojego kanału i zaimportować je do innej witryny. W rzadkich przypadkach treść może mieć taki charakter, że uzasadnia natychmiastowe zamknięcie konta. To jest decyzja właściciela węzła, a nie decyzja $Projectname.
Jeśli zazwyczaj i regularnie publikujesz treści dla dorosłych lub obraźliwe, MOCNO zachęcamy do oznaczenia swojego konta jako „NSFW” (Not Safe For Work). Zapobiegnie to wyświetlaniu Twojego zdjęcia profilowego w katalogu, z wyjątkiem przeglądających, którzy zdecydowali się wyłączyć „tryb bezpieczny”. Jeśli administratorzy katalogu uznają Twoje zdjęcie profilowe za nieobyczajne lub obraźliwe, administrator katalogu MOŻE oznaczyć Twoje zdjęcie profilowe jako NSFW. Obecnie nie ma oficjalnego mechanizmu do zakwestionowania lub cofnięcia tej decyzji, dlatego NALEŻY oznaczyć własne konto jako NSFW, jeśli może być nieodpowiednie dla ogółu odbiorców.

View File

@@ -13,7 +13,7 @@ W przeciwieństwie do innych usług, $Projectname oferuje Ci możliwość tworze
[i]Potraktuj swój profil jako podstawowe informacje o sobie, które przekazujesz innym osobom.[/i]
[b]Kanał[/b]
Podczas rejestracji tworzysz swój pierwszy [i]kanał[/i]. Podobnie jak w przypadku profili, możesz mieć kilka kanałów. Na początku może to być nieco zagmatwane, ale wyjaśnijmy to. Masz już jeden kanał. Możesz używać go dla publicznie, aby komunikować się z ludźmi w codziennym życiu. Ale być może jesteś zapalonym czytelnikiem książek i wielu ludzi się tym nudzi. Otwierasz więc [i]drugi kanał[/i] tylko dla miłośników książek, na którym wszyscy mogą rozmawiać o książkach tyle, ile chcesz. Oczywiście jest to nowy strumień postów, z nowym profilem (... lub nowymi profilami ...) i zupełnie innymi kontaktami. Niektóre połączenia mogą istnieć w obu kanałach, ale będą takie, które dotyczą tylko jednego z nich. Ty sam po prostu przełączasz się między nimi, tak jak w prawdziwym życiu, kiedy rozmawiasz z ludźmi, których spotykasz na ulicy lub z osobami, które spotykasz specjalnie, aby porozmawiać o książkach. Możesz nawet połączyć się ze sobą lub lepiej: z innym kanałem. :)
Podczas rejestracji tworzysz swój pierwszy [i]kanał[/i]. Podobnie jak w przypadku profili, możesz mieć kilka kanałów. Na początku może to być nieco zagmatwane, ale wyjaśnijmy to. Masz już jeden kanał. Możesz używać go dla publicznie, aby komunikować się z ludźmi w codziennym życiu. Ale być może jesteś zapalonym czytelnikiem książek i wielu ludzi się tym nudzi. Otwierasz więc [i]drugi kanał[/i] tylko dla miłośników książek, na którym wszyscy mogą rozmawiać o książkach tyle, ile chcesz. Oczywiście jest to nowy strumień wpisów, z nowym profilem (... lub nowymi profilami ...) i zupełnie innymi kontaktami. Niektóre połączenia mogą istnieć w obu kanałach, ale będą takie, które dotyczą tylko jednego z nich. Ty sam po prostu przełączasz się między nimi, tak jak w prawdziwym życiu, kiedy rozmawiasz z ludźmi, których spotykasz na ulicy lub z osobami, które spotykasz specjalnie, aby porozmawiać o książkach. Możesz nawet połączyć się ze sobą lub lepiej: z innym kanałem. :)
[i]Pomyśl o kanale jako o różnych przestrzeniach poświęconych różnym tematom, w których spotykasz się z różnymi ludźmi.[/i]
#include doc/macros/pl/main_footer.bb;

View File

@@ -14,7 +14,7 @@ któremu chcesz zrobić niespodziankę. W tym przypadku ustawiasz "Pokaż" grupi
</p>
<dl class="text-info dl-terms-large dl-horizontal">
<dt style="width: 3em;">Wskazówka!</td>
<dt style="width: 3em;">Wskazówka!</dt>
<dd style="margin-left: 4em;">
Kolor obramowania każdego kanału wskazuje, czy ten kanał &mdash; lub jedną z grup,
do której należy &mdash; będzie mieć dostęp do wpisu. Kolor obramowania będzie

View File

@@ -1,6 +1,6 @@
[h3]Wtyczki/Dodatki[/h3]
[list=1]
[*] abcjsplugin - tworzenie zapisów nitowych w swoich wpisach
[*] abcjsplugin - tworzenie zapisów nutowych w swoich wpisach
[*] adultphotoflag - zapobiega wyświetlaniu zdjęć NSFW w albumach publicznych
[*] authchoose - wysyłanie potwierdzenia tożsamości tylko do witryn znajomych
[*] b2tbtn - zapewnia przycisk powodujący przejście bezpośrednio na górę strony, jeśli przewinie się dużo treści dół okna
@@ -10,7 +10,7 @@
[*] calc - kalkulator naukowy
[*] chess - interaktywne gry w szachy z uwzględnieniem tożsamości międzydomenowej
[*] chords - generowanie wykresów palcowania i alternatyw dla każdego znanego akordu gitarowego
[*] custom_home - ustawianie własnej strony jako strony początkowej huba
[*] custom_home - ustawianie własnej strony jako strony początkowej węzła
[*] diaspora - emulator protokołu Diaspora
[*] dirstats - wyświetlanie interesujących statystyk generowanych przez serwer katalogowy
[*] docs - alternatywne strony dokumentacji
@@ -18,7 +18,7 @@
[*] dreamhost - zapewnia bardziej niezawodną usługę na hostingu współdzielonym Dreamhost
[*] dwpost - krzyżowe wpisy do Dreamwidth
[*] emojione - zezwala na uzywanie emojis jako emotikonów
[*] extcron - stosowanie zewnętrznej usługi cron do uruchamiania zaplanowanych zadań huba
[*] extcron - stosowanie zewnętrznej usługi cron do uruchamiania zaplanowanych zadań węzła
[*] firefox - dostarcza link do zainstalowania API Sharing Firefoxa
[*] flattrwidget - dostarcza przyciski "Flattr Us"
[*] flip - tworzenie odwróconego tekstu
@@ -28,7 +28,7 @@
[*] gnusoc - protokół GNU-Social (OStatus). W tworzeniu.
[*] hexit - narzędzie do konwersji szesnastkowej
[*] hilite - umożliwia podświetlanie bloków kodu, specyficzne dla języka programowania, zawartych we wpisach
[*] hubwall - wysyłanie wiadomosci e-mail administratora na wszystkie konta w hubie
[*] hubwall - wysyłanie wiadomosci e-mail administratora na wszystkie konta w węźle
[*] ijpost - krzyżówe wpisy do Insanejournal
[*] irc - połączenie z czatami IRC
[*] jappixmini - czat XMPP
@@ -51,7 +51,7 @@
[*] noembed - używanie noembed.com jako dodatku do natywnej funkcjonalności oembed w $Projectname (obecnie nie działa)
[*] nofed - zapobiega "federacji" wpisów w kanale, utrzymuje całą interakcję na stronie właściciela kanału
[*] nsabait - dodawaj do swoich wpisów losowe hashtagi związane z terroryzmem
[*] nsfw - bardzo polecana wtyczka do zwijania postów z nieodpowiednimi treściami
[*] nsfw - bardzo polecana wtyczka do zwijania wpisów z nieodpowiednimi treściami
[*] openclipatar - wybór zdjęcia profilowego spośród setek obrazów bez tantiem
[*] openid - uwierzytelnianie OpenID i serwer OpenID. Twój adres URL OpenID to [observer.baseurl]/id/[observer.webname]
[*] opensearch - umożliwienie swojej witrynie stania się dostawcą wyszukiwania w przeglądarce
@@ -81,7 +81,7 @@
[*] statusnet - wpisy krzyżówe do GNU-social i StatusNet [zrl=[baseurl]/help/addons_gnusocial]Posting To Gnu Social[/zrl]
[*] std_embeds - umożłiwia niefiltrowane osadzanie dla popularnych dostawców strumieni, takich jak youtube, vimeo i soundcloud
[*] superblock - bardzo zalecane - całkowite blokowanie obraźliwuch kanałów w swoim strumieniu
[*] testdrive - zmienia hub w witrynę testową z kontami, które wygasają po okresie próbnym
[*] testdrive - zmienia węzęł w witrynę testową z kontami, które wygasają po okresie próbnym
[*] tictac - 3D tic-tac-toe
[*] torch - aplikacja podświetlania (flashlight)
[*] tour - prezentacja funkcji dla nowych członków

View File

@@ -12,7 +12,7 @@ Ikona. Pobierz ikonę $Projectname znajdującą się pod tym linkiem, po zapisan
https://framagit.org/hubzilla/core/blob/master/images/rm-32.png
Nazwa. Nadaj aplikacji odpowiednią nazwę. Wywołaj swoją witrynę hubzilli. Możesz preferować r2g.
Nazwa. Nadaj aplikacji odpowiednią nazwę. Wywołaj swoją witrynę Hubzilli. Możesz preferować r2g.
Opis. Użyj tego pola, aby opisać przeznaczenie aplikacji. Dodaj coś o efekcie użycia krzyżowego wysyłania z $Projectname do GNUsocial.

View File

@@ -1,12 +1,12 @@
### Przegląd
$Projectname to więcej niż prosta aplikacja internetowa. Jest to złożony system komunikacyjny, który bardziej przypomina serwer poczty elektronicznej niż serwer WWW. Aby zapewnić niezawodność i wydajność, wiadomości są dostarczane w tle i umieszczane w kolejce do późniejszego dostarczenia, gdy lokacje są wyłączone. Ten rodzaj funkcjonalności wymaga nieco więcej zasobów hosta niż typowy dziennik. Nie każdy dostawca hostingu PHP-MySQL będzie w stanie obsługiwać $Projectname. Tak więc, przed instalacją zapoznaj się z wymaganiami i potwierdź je u dostawcy usług hostingowych.
$Projectname to więcej niż prosta aplikacja internetowa. Jest to złożony system komunikacyjny, który bardziej przypomina serwer poczty elektronicznej niż serwer WWW. Aby zapewnić niezawodność i wydajność, wiadomości są dostarczane w tle i umieszczane w kolejce do późniejszego dostarczenia, gdy lokacje są wyłączone. Ten rodzaj funkcjonalności wymaga nieco więcej zasobów hosta niż typowy blog. Nie każdy dostawca hostingu PHP-MySQL będzie w stanie obsługiwać $Projectname. Tak więc, przed instalacją zapoznaj się z wymaganiami i potwierdź je u dostawcy usług hostingowych.
Bardzo staraliśmy się, aby Hubzilla działała na zwykłych platformach hostingowych, takich jak te używane do hostowania blogów Wordpress i stron internetowych Drupal. Będzie ona działać na większości systemów VPS Linux. Platformy Windows LAMP, takie jak XAMPP i WAMP, nie są obecnie oficjalnie obsługiwane, jednak mile widziane są poprawki, jeśli uda Ci się je uruchomić.
### Gdzie można znaleźć więcej pomocy
Jeśli napotkasz problemy lub sam masz jakiś problem, które nie zostały opisane w tej dokumentacji, poinformuj nas o tym za pośrednictwem narzędzia do [śledzenia problemów na Github](https://framagit.org/hubzilla/core/issues). Prosimy o jak najdokładniejsze opisanie swojego środowiska operacyjnego i podanie jak największej ilości informacji o wszelkich komunikatach o błędach, które mogą się pojawić, abyśmy mogli zapobiec ich występowaniu w przyszłości. Ze względu na dużą różnorodność istniejących systemów operacyjnych i platform PHP możemy mieć ograniczone możliwości debugowania instalacji PHP lub pozyskiwania brakujących modułów, ale dołożymy wszelkich starań, aby rozwiązać wszelkie ogólne problemy z kodem.
Jeśli napotkasz problemy lub sam masz jakiś problem, które nie zostały opisane w tej dokumentacji, poinformuj nas o tym za pośrednictwem narzędzia do [śledzenia problemów na serwisie Framagit](https://framagit.org/hubzilla/core/issues). Prosimy o jak najdokładniejsze opisanie swojego środowiska operacyjnego i podanie jak największej ilości informacji o wszelkich komunikatach o błędach, które mogą się pojawić, abyśmy mogli zapobiec ich występowaniu w przyszłości. Ze względu na dużą różnorodność istniejących systemów operacyjnych i platform PHP możemy mieć ograniczone możliwości debugowania instalacji PHP lub pozyskiwania brakujących modułów, ale dołożymy wszelkich starań, aby rozwiązać wszelkie ogólne problemy z kodem.
### Zanim zaczniesz
@@ -20,25 +20,25 @@ POWINNO się używać SSL. Jeśli używasz SSL, MUSISZ użyć certyfikatu uznawa
Przetestuj swój certyfikat przed instalacją. Narzędzie internetowe do testowania certyfikatu jest dostępne pod adresem http://www.digicert.com/help/. Odwiedzając witrynę po raz pierwszy, użyj adresu URL SSL (https://), jeśli protokół SSL jest dostępny. Pozwoli to uniknąć późniejszych problemów. Procedura instalacji nie pozwoli na użycie certyfikatu, który nie jest zaufany dla przeglądarki.
To ograniczenie zostało wprowadzone, ponieważ Twoje publiczne wpisy mogą zawierać odniesienia do obrazów na Twoim hubie. Inni członkowie przeglądający swój strumień w innych centrach otrzymają ostrzeżenia, jeśli Twój certyfikat nie jest zaufany w ich przeglądarce internetowej. To zmyli wiele osób, ponieważ jest to zdecentralizowana sieć i otrzymają ostrzeżenie o Twoim hubie podczas przeglądania własnego huba i mogą pomyśleć, że ich własny hub ma problem. Te ostrzeżenia są bardzo techniczne i przerażające dla niektórych osób, z których wielu nie będzie wiedziało, jak postępować, z wyjątkiem przestrzegania zaleceń przeglądarki. Jest to destrukcyjne dla społeczności. To powiedziawszy, zdajemy sobie sprawę z problemów związanych z obecną infrastrukturą certyfikatów i zgadzamy się, że istnieje wiele problemów, ale to nie zmienia wymagania.
To ograniczenie zostało wprowadzone, ponieważ Twoje publiczne wpisy mogą zawierać odniesienia do obrazów na Twoim węźle. Inni członkowie przeglądający swój strumień na innych węzłach otrzymają w swojej przeglądarce ostrzeżenia, jeśli Twój certyfikat nie jest zaufany. To może zmylić wiele osób, ponieważ jest to zdecentralizowana sieć i otrzymają ostrzeżenie o Twoim węźle podczas przeglądania własnego węzła i mogą pomyśleć, że ich własny węzeł ma problem. Te ostrzeżenia są bardzo techniczne i przerażające dla niektórych osób, z których wielu nie będzie wiedziało, jak postępować i podporządkuje się zaleceniom przeglądarki. Jest to destrukcyjne dla społeczności. Zdajemy sobie sprawę z problemów związanych z obecną infrastrukturą certyfikatów i zgadzamy się, że istnieje wiele problemów, ale to nie zmienia wymagania - szyfrowanie połączeń HTTP jest konieczne.
Bezpłatne certyfikaty zgodne z przeglądarkami są dostępne od dostawców, takich jak StartSSL i LetsEncrypt.
Bezpłatne certyfikaty zgodne z przeglądarkami są dostępne od dostawców, takich jak StartSSL czy LetsEncrypt.
Jeśli NIE używasz SSL, może wystąpić opóźnienie do minuty dla startowego skryptu instalacyjnego - podczas sprawdzania portu SSL, aby zobaczyć, czy tam jest wszystko w porządku. Podczas komunikowania się z nowymi witrynami Hubzilla zawsze najpierw próbuje połączyć się z portem SSL, zanim powróci do mniej bezpiecznego połączenia. Jeśli nie używasz SSL, twój serwer WWW NIE MOŻE w ogóle nasłuchiwać na porcie 443.
Jeśli NIE używasz SSL, może wystąpić opóźnienie do minuty dla startowego skryptu instalacyjnego - podczas sprawdzania portu SSL, aby zobaczyć, czy tam jest wszystko w porządku. Podczas komunikowania się z nowymi witrynami Hubzilla zawsze najpierw próbuje połączyć się z portem SSL, zanim powróci do mniej bezpiecznego połączenia. Jeśli nie używasz SSL, Twój serwer WWW NIE MOŻE w ogóle nasłuchiwać na porcie 443.
Jeśli używasz LetsEncrypt do dostarczania certyfikatów i tworzenia pliku pod _well-known_ lub _acme-challenge_, aby LetsEncrypt mógł zweryfikować własność domeny, usuń lub zmień nazwę katalogu _.well-known_ zaraz po wygenerowaniu certyfikatu. $Projectname zapewni własną procedurę obsługi usług *.well-know* po zainstalowaniu, a istniejący katalog w tej lokalizacji może uniemożliwić poprawne działanie niektórych z tych usług. Nie powinno to stanowić problemu w przypadku Apache, ale może to być problem z Nginx lub innymi platformami serwera internetowego.
Jeśli używasz LetsEncrypt do dostarczania certyfikatów i tworzenia pliku pod _well-known_ lub _acme-challenge_, aby LetsEncrypt mógł zweryfikować własność domeny, usuń lub zmień nazwę katalogu _.well-known_ zaraz po wygenerowaniu certyfikatu. $Projectname zapewni własną procedurę obsługi usług *.well-know* po zainstalowaniu, a istniejący katalog w tej lokalizacji może uniemożliwić poprawne działanie niektórych z tych usług. Nie powinno to stanowić problemu w przypadku Apache, ale może to być problem z Nginx lub innymi serwerami internetowymi.
### Wdrożenie
Nowy hub można wdrożyć na kilka sposobów:
Nowy węzeł można wdrożyć na kilka sposobów:
* ręczna inastalaja na istniejącym serwerze;
* automatyczna instalacja na istniejącym serwerze przy użyciu skryptu instalacyjnego;
* automatyczne wdrożenie przy użyciu prywatnego serwera wirtualnego OpenShift (VPS).)
* automatyczne wdrożenie przy użyciu prywatnego serwera wirtualnego OpenShift (VPS).
### Wymagania
* Apache z włączonym modułem _mod-rewrite_ i ustawioną dyrektywą "AllowOverride All", tak aby można było stosować plik _.htaccess_. Niektóre osoby z powodzeniem stosowały Nginx czy Lighttpd.Przykładowe skrypty konfiguracyjne są dostępne na tej platformie w [doc/install](). Apache and Nginx mają najlepsze wsparcie.
* Apache z włączonym modułem _mod-rewrite_ i ustawioną dyrektywą "AllowOverride All", tak aby można było stosować plik _.htaccess_. Niektóre osoby z powodzeniem stosowały Nginx czy Lighttpd. Przykładowe skrypty konfiguracyjne są dostępne na tej platformie w [doc/install](). Apache and Nginx mają najlepsze wsparcie.
* PHP 7.1 lub w wersji wyższej.
* _Proszę mieć na uwadze, że w niektórych środowiskach hostinu współdzielonego, wersja wiersza poleceń PHP różni się od wersji serwera internetowego_
@@ -204,7 +204,7 @@ jest nieco bardziej restrykcyjny w zakresie dozwolonych rodzajów komunikacji. W
* _gnusoc_ - protokół społecznościowy GNU, używany przez GNU-Social, Mastodon i kilka innych społeczności. Ten dodatek wymaga najpierw zainstalowania usługi _pubsubhubbub_ (także dodatku).
Każdy członek Twojej siatki musi indywidualnie zdecydować, czy zezwolić na te protokoły, ponieważ mogą one kolidować z kilkoma pożądanymi podstawowymi funkcjami i możliwościami Hubzilla (takimi jak migracja kanałów i klonowanie). Robi się to
Każdy członek Twojej sieci musi indywidualnie zdecydować, czy zezwolić na te protokoły, ponieważ mogą one kolidować z kilkoma pożądanymi podstawowymi funkcjami i możliwościami Hubzilla (takimi jak migracja kanałów i klonowanie). Robi się to
na swojej stronie _Ustawienia_ -> _Ustawienia funkcji i dodatków_. Administrator może również ustawić:
util/config system.diaspora_allowed 1
@@ -214,7 +214,7 @@ i włączać te protokoły automatycznie dla wszystkich nowo tworzonych kanałó
### Klasy usług
Klasy usług pozwalają na ustawienie limitów zasobów systemowych poprzez ograniczenie tego, co mogą robić poszczególne konta, w tym przechowywania plików i najwyższych limitów wpisów. Zdefiniuj niestandardowe klasy usług zgodnie ze swoimi potrzebami w pliku _.htconfig.php_. Na przykład utwórz klasę standard i premium, używając następujących wierszy:
Klasy usług pozwalają na ustawienie limitów zasobów systemowych poprzez ograniczenie tego, co mogą robić poszczególne konta, w tym przechowywania plików i najwyższych limitów wpisów. Zdefiniuj niestandardowe klasy usług zgodnie ze swoimi potrzebami w pliku _.htconfig.php_. Dla przykładu utwórzmy klasę standard i premium, używając następujący kod:
// Service classes
@@ -263,21 +263,22 @@ Aby zastosować klasę usług do istniejącego konta, użyj narzędzia wiersza p
util/service_class --account=5 firstclass
* ustawienie konta, które jest właścicielem kanału `bdziennikchan` na klasę _firstclass_ (z potwierdzeniem)
* ustawienie konta, które jest właścicielem kanału `blogchan` na klasę _firstclass_ (z potwierdzeniem)
util/service_class --channel=bdziennikchan firstclass
util/service_class --channel=blogchan firstclass
**Opcje limitu klas usług**
##### Opcje limitów klas usług:
* _photo_upload_limit_ - maksymalna łączna liczba bajtów na zdjęcia
* _photo_upload_limit_ - maksymalna łączna powierzchnia dysku na przesłane pliki (w bajtach)
* _attach_upload_limit_ - maksymalna powierzchnia dysku na przesyłane załączniki plikow (w bajtach)
* _total_items_ - maksymalna liczba wpisów na najwyższym poziomie
* _total_pages_ - maksymalna liczba stron comanche
* _total_pages_ - maksymalna liczba stron Comanche
* _total_identities_ - maksymalna liczba kanałów posiadanych na koncie
* _total_channels_ - maksymalna liczba kanałów
* _total_feeds_ - maksymalna liczba kanałów RSS
* _attach_upload_limit_ - maksymalna pojemność przesyłania plików (w bajtach)
* _minimum_feedcheck_minutes_ - najniższe ustawienie dozwolone dla odpytywania kanałów RSS
* _chatrooms_ - maksymalna liczba czatów
* _chatters_inroom_ - maksymalna liczba rozmówców w czacie
@@ -312,7 +313,7 @@ Na stronie katalogu kanałów może pojawiać się chmura słów kluczowych. Je
util/config system disable_directory_keywords 1
Jeśli twój hub pracuje w trybie autonomicznym, ponieważ nie chcesz łączyć się z globalną siecią, możesz zamiast tego ustawić opcję systemową _directory_server_ na wartość pustą:
Jeśli twój węzeł pracuje w trybie autonomicznym, ponieważ nie chcesz łączyć się z globalną siecią, możesz zamiast tego ustawić opcję systemową _directory_server_ na wartość pustą:
util/config system directory_server ""
@@ -326,7 +327,7 @@ Istnieje kilka sposobów, w jakie może to się nie powieść i pozostawić syst
Ze względów bezpieczeństwa w systemie nie ma strony internetowej ani interfejsu, który daje dostęp administratora. Jeśli potrzebujesz poprawić sytuację, w której system nie ma konta administratora, musisz to zrobić edytując tabelę kont w bazie danych. Nie ma innego wyjścia. Aby to zrobić, będziesz musiał zlokalizować wpis w tabeli kont, który należy do żądanego administratora i ustawić _account_roles_ dla tego wpisu na _4096_. Będziesz wtedy mógł uzyskać dostęp do strony administratora z menu profilu twojego systemu lub bezpośrednio na ścieżce _/admin_.
Hub może mieć wielu administratorów i nie ma ograniczeń co do ich liczby. Powtórz powyższą procedurę dla każdego konta, któremu chcesz przyznać uprawnienia administracyjne.
Węzeł może mieć wielu administratorów i nie ma ograniczeń co do ich liczby. Powtórz powyższą procedurę dla każdego konta, któremu chcesz przyznać uprawnienia administracyjne.
### Rozwiązywanie problemów
@@ -340,17 +341,16 @@ W przypadku błędów "500: problemy mogą być często rejestrowane w dziennika
Istnieją trzy różne obiekty dziennika.
**Pierwsza to dziennik błędów bazy danych**. Jest on używane tylko wtedy, gdy tworzy się plik o specyficznej nazwie *dbfail.out* w folderze głównym swojej witryny i pozwala na zapisywanie w nim przez serwer WWW. Jeśli masz jakiekolwiek zapytania do bazy danych, które nie powiodły się, wszystkie są zgłaszane tutaj. Zwykle wskazują na literówki w naszych zapytaniach, ale występują również w przypadku rozłączenia serwera bazy danych lub uszkodzenia tabel. W rzadkich przypadkach zobaczymy tutaj warunki wyścigu, w których dwa procesy próbowały utworzyć wpis *xchan* lub *cache* z tym samym identyfikatorem. Należy zbadać wszelkie inne błędy (zwłaszcza błędy uporczywe).
**Pierwsza to dziennik błędów bazy danych**. Jest on używane tylko wtedy, gdy utworzy się plik o nazwie **_dbfail.out_** w folderze głównym swojej witryny i pozwala na zapisywanie w nim przez serwer WWW. Jeśli masz jakiekolwiek zapytania do bazy danych, które nie powiodły się, wszystkie są zgłaszane tutaj. Zwykle wskazują na literówki w naszych zapytaniach, ale występują również w przypadku rozłączenia serwera bazy danych lub uszkodzenia tabel. W rzadkich przypadkach zobaczymy tutaj warunki wyścigu, w których dwa procesy próbowały utworzyć wpis *xchan* lub *cache* z tym samym identyfikatorem. Należy zbadać wszelkie inne błędy (zwłaszcza błędy uporczywe).
**Drugi to dziennik błędów PHP**. Jest tworzony przez procesor języka i zgłasza tylko problemy powstałe w środowisku językowym. Znowu mogą to być błędy składniowe lub błędy programistyczne, ale generalnie są one fatalne i skutkują "białym ekranem";
**Drugi to dziennik błędów PHP**. Plik **_php.out_** jest tworzony przez procesor języka i zgłasza tylko problemy powstałe w środowisku językowym. Znowu mogą to być błędy składniowe lub błędy programistyczne, ale generalnie są one fatalne i skutkują "białym ekranem";
na przykład PHP kończy działanie. Prawdopodobnie powinieneś zajrzeć do tego pliku też, jeśli coś pójdzie nie tak, co nie powoduje białego ekranu. Często zdarza się, że plik ten jest pusty przez wiele dni.
Na dole dostarczonego pliku *.htconfig.php* znajduje się kilka linii, które, jeśli nie są zakomentowane, włączają dziennik PHP (niezwykle przydatny do znajdowania źródła błędów białego ekranu). Nie jest to robione domyślnie ze względu na potencjalne problemy z własnością pliku dziennika i uprawnieniami do zapisu oraz fakt, że domyślnie nie ma rotacji pliku dziennika.
**Trzeci to "dziennik aplikacji"**. Jest to używane przez Hubzillę do zgłaszania tego, co dzieje się w programie i zwykle zapisywane są tu wszelkie trudności lub nieoczekiwane dane, które otrzymaliśmy. Czasami zgłasza się tu również komunikaty
o stanie "pulsu", aby wskazać, że osiągnęliśmy określony punkt w skrypcie. Jest to dla nas najważniejszy plik dziennika, ponieważ tworzymy go samodzielnie wyłącznie w celu zgłaszania stanu zadań w tle i wszystkiego, co wydaje się dziwne lub nie na miejscu. To może nie być śmiertelne, ale może po prostu nieoczekiwane. Jeśli wykonujesz zadanie i występuje problem, daj nam znać, co znajduje się w tym pliku, gdy wystąpił problem. Proszę nie wysyłaj mi 100 milionów zrzutów, tylko mnie wkurzysz! Tylko kilka odpowiednich wierszy, abym mógł wykluczyć kilkaset tysięcy wierszy kodu i skoncentrować się na tym, gdzie zaczyna się pojawiać problem.
**Trzeci to "dziennik aplikacji"**. Jest to używane przez Hubzillę do zgłaszania tego, co dzieje się w programie i zwykle zapisywane są tu wszelkie trudności lub nieoczekiwane dane, które otrzymaliśmy. Jego nazwę (ścieżkę) trzeba podać na stronie "Administracja - Logi" (/admin/logs), np. *hubzilla.log* wskazuje na plik o tej nazwie zlokalizowany w katalogu głównym Hubzilla. Czasem zgłaszane są tu również komunikaty o stanie "pulsu", aby wskazać, że osiągnęliśmy określony punkt w skrypcie. Jest to dla nas najważniejszy plik dziennika, ponieważ tworzymy go samodzielnie wyłącznie w celu zgłaszania stanu zadań w tle i wszystkiego, co wydaje się dziwne lub nie na miejscu. Te błędy mogą być "śmiertelne", ale też niegroźne i po prostu nieoczekiwane. Jeśli wykonujesz zadanie i występuje problem, daj nam znać, co znajduje się w tym pliku, gdy wystąpił problem. Proszę nie wysyłaj nam 100 milionów zrzutów, bo tylko nas wkurzysz! Tylko kilka odpowiednich wierszy, ab można było wykluczyć kilkaset tysięcy wierszy kodu i skoncentrować się na tym, gdzie zaczyna się pojawiać problem.
To są dzienniki Twojej witryny, a nie moje. Zgłaszamy poważne problemy na każdym poziomie dziennika. Gorąco polecam poziom dziennika *DEBUG* dla większości witryn. Dostarcza on trochę dodatkowych informacji i nie tworzy dużych plików dziennika. Kiedy pojawia się problem, który uniemożliwia wszelkie próby śledzenia, możesz wtedy włączyć na krótki czas poziom *DATA*, aby uchwycić wszystkie szczegóły struktur, z którymi mieliśmy do czynienia w tym czasie. Ten poziom dziennika zajmuje dużo miejsca, więc jest zalecany tylko na krótkie okresy lub w przypadku witryn testowych dla programistów.
To są dzienniki Twojego serwisu. Zgłaszamy poważne problemy na każdym poziomie dziennika. Gorąco polecam poziom dziennika *DEBUG* dla większości witryn. Dostarcza on trochę dodatkowych informacji i nie tworzy dużych plików dziennika. Kiedy pojawia się problem, który uniemożliwia wszelkie próby śledzenia, możesz wtedy włączyć na krótki czas poziom *DATA*, aby uchwycić wszystkie szczegóły struktur, z którymi mieliśmy do czynienia w tym czasie. Ten poziom dziennika zajmuje dużo miejsca, więc jest zalecany tylko na krótkie okresy lub w przypadku witryn testowych dla programistów.
Zalecam skonfigurowanie *logrotate* zarówno dla dziennika php, jak i dziennika aplikacji. Zazwyczaj co tydzień lub dwa zaglądam do *dbfail.out*, naprawiam zgłoszone problemy i zaczynam od nowego pliku. Podobnie jest z plikiem dziennika PHP. Odwołuję się do tego od czasu do czasu, aby sprawdzić, czy jest coś, co wymaga naprawy.

View File

@@ -1,11 +1,11 @@
### Hub Snapshot Tools
### Narzędzia migawek węzła
Programiści Hubzilli często muszą przełączać się między gałęziami, które mogą
mieć niekompatybilne schematy lub zawartość bazy danych. Poniższe dwa skrypty
tworzą i przywracają pełne migawki instancji Hubzilli, w tym zarówno główny
katalog sieciowy, jak i stan całej bazy danych. Każdy skrypt wymaga pliku
konfiguracyjnego o nazwie *hub-snapshot.conf* znajdującego się w tym samym
folderze i zawiera on określone katalogi i szczegóły bazy danych huba.
folderze i zawiera on określone katalogi i szczegóły bazy danych węzłaa.
### Konfiguracja

View File

@@ -1,9 +1,9 @@
[h2]Dokumentacja dla administratorów huba[/h2]
[h3]Wdrozenie swojego huba[/h3]
[h2]Dokumentacja dla administratorów węzła[/h2]
[h3]Wdrozenie swojego węzła[/h3]
[zrl=[baseurl]/help/install]Instalacja[/zrl]
[zrl=[baseurl]/help/red2pi]Instalowanie $Projectname na Raspberry Pi[/zrl]
[zrl=[baseurl]/help/Hubzilla_on_OpenShift]$Projectname na OpenShift[/zrl]
[h3]Utrzymywanie swojego huba[/h3]
[h3]Utrzymywanie swojego węzła[/h3]
[zrl=[baseurl]/help/troubleshooting]Wskazówki dotyczące rozwiązywania problemów[/zrl]
[zrl=[baseurl]/help/theme_management]Zarządzanie motywami[/zrl]
[zrl=[baseurl]/help/hidden_configs]Poprawianie ukrytych konfiguracji $Projectname[/zrl]

View File

@@ -5,15 +5,15 @@
$Projectname Community Server to oprogramowanie typu Open Source, które jest utrzymywane przez "społeczność" - zasadniczo nieopłacanych ochotników. Nikt nie jest odpowiedzialny za naprawianie błędów. Pracujemy razem, aby oprogramowanie i sieć działały płynnie i bez błędów. Jesteś członkiem tej społeczności, więc potrzebujemy również Twojej pomocy, aby zapewnić wysokiej jakości oprogramowanie. Nie ma mitycznych "programistów", którzy w magiczny sposób wszystko naprawiają. Do nas wszystkich należy włączenie się i pomoc.
Pierwszą rzeczą, którą musisz zrobić, jest porozimieć się z administratorem huba - osobą, która obsługuje Twoją witrynę i zarządza nią. Znajdują się ona w wyjątkowej sytuacji, ponieważ ma dostęp do wewnętrznego oprogramowania i bazy danych oraz [b]plików dziennika[/b] i będzie musiała zaangażować się w naprawę problemu. Inne osoby "w sieci" nie mogą naprawdę Ci tym pomóc. Pierwszą rzeczą, jaką musi zrobić administrator huba, jest przejrzenie dzienników i podjecie próby odtworzenia problemu. Dlatego staraj się być tak pomocny i uprzejmy, jak to tylko możliwe, pomagając mu przyjrzeć się problemowi.
Pierwszą rzeczą, którą musisz zrobić, jest porozimieć się z administratorem węzła - osobą, która obsługuje Twoją witrynę i zarządza nią. Znajdują się ona w wyjątkowej sytuacji, ponieważ ma dostęp do wewnętrznego oprogramowania i bazy danych oraz [b]plików dziennika[/b] i będzie musiała zaangażować się w naprawę problemu. Inne osoby "w sieci" nie mogą naprawdę Ci tym pomóc. Pierwszą rzeczą, jaką musi zrobić administrator węzła, jest przejrzenie dzienników i podjecie próby odtworzenia problemu. Dlatego staraj się być tak pomocny i uprzejmy, jak to tylko możliwe, pomagając mu przyjrzeć się problemowi.
Aby znaleźć swojego administratora huba (jeśli nie wiesz, kim on jest), zajrzyj na [url=[baseurl]/siteinfo] stronę[/url]. Jeśli nie podał on żadnych informacji kontaktowych na tej stronie lub nie podał "Impressum", zobacz [url=[baseurl]/siteinfo.json]podsumowanie informacji o tej witrynie[/url] znajdujące się pod nagłówkiem "admin:".
Aby znaleźć swojego administratora węzła (jeśli nie wiesz, kim on jest), zajrzyj na [url=[baseurl]/siteinfo] stronę[/url]. Jeśli nie podał on żadnych informacji kontaktowych na tej stronie lub nie podał "Impressum", zobacz [url=[baseurl]/siteinfo.json]podsumowanie informacji o tej witrynie[/url] znajdujące się pod nagłówkiem "admin:".
Zdecydowanie zaleca się, aby administratorzy huba wypełniali raporty o błędach, tak aby możliwe było dołączenie odpowiedniego plik dziennika i informacji z bazy danych istotnych dla problemu oraz aby byli oni gotowi do wypróbowania rozwiązań i testów uzupełniających. Bez tego poziomu współpracy rozwiązanie problemu może nie być możliwe.
Zdecydowanie zaleca się, aby administratorzy węzła wypełniali raporty o błędach, tak aby możliwe było dołączenie odpowiedniego plik dziennika i informacji z bazy danych istotnych dla problemu oraz aby byli oni gotowi do wypróbowania rozwiązań i testów uzupełniających. Bez tego poziomu współpracy rozwiązanie problemu może nie być możliwe.
[h3]Jestem administratorem huba, co mam zrobić?[/h3]
[h3]Jestem administratorem węzła, co mam zrobić?[/h3]
Oprogramowania zapewniające usługę sieciową jest typu Open Source i jest dostępne do wglądu. Zachęcamy wszystkich do zapoznania się z kodem i zobaczenia, jak wszystko działa i sprawdzenia, czy nie robimy nic złego lub niedbałego. Jeśli został zgłoszony komunikat o błędzie, często można przeszukać pliki źródłowe tego komunikatu o błędzie i dowiedzieć się, co go spowodowało. Dzięki tym informacjom i plikom dziennika serwisu możliwe będzie ustalenie sekwencji zdarzeń prowadzących do błędu. Problem mogą powodować również serwisy zewnętrzne i jego źródłem wcale nie musi być Twój serwis, ale inne miejsce w sieci. Spróbuj określić punkty końcowe komunikacji (huby lub serwisy), których dotyczy problem i skontaktuj się z administratorem tego serwisu lub tych serwisów. Spróbuj podać czas zdarzenia, w którym coś poszło nie tak, aby można go było znaleźć w dziennikach. Współpracuj z innymi administratorami, aby spróbować znaleźć przyczynę problemu. Pliki dziennika Twoim przyjacielem. Kiedy w oprogramowaniu dzieje się coś, czego się nie spodziewaliśmy, prawie zawsze zostało to zarejestrowane.
Oprogramowania zapewniające usługę sieciową jest typu Open Source i jest dostępne do wglądu. Zachęcamy wszystkich do zapoznania się z kodem i zobaczenia, jak wszystko działa i sprawdzenia, czy nie robimy nic złego lub niedbałego. Jeśli został zgłoszony komunikat o błędzie, często można przeszukać pliki źródłowe tego komunikatu o błędzie i dowiedzieć się, co go spowodowało. Dzięki tym informacjom i plikom dziennika serwisu możliwe będzie ustalenie sekwencji zdarzeń prowadzących do błędu. Problem mogą powodować również serwisy zewnętrzne i jego źródłem wcale nie musi być Twój serwis, ale inne miejsce w sieci. Spróbuj określić punkty końcowe komunikacji (węzły lub serwisy), których dotyczy problem i skontaktuj się z administratorem tego serwisu lub tych serwisów. Spróbuj podać czas zdarzenia, w którym coś poszło nie tak, aby można go było znaleźć w dziennikach. Współpracuj z innymi administratorami, aby spróbować znaleźć przyczynę problemu. Pliki dziennika Twoim przyjacielem. Kiedy w oprogramowaniu dzieje się coś, czego się nie spodziewaliśmy, prawie zawsze zostało to zarejestrowane.
[h3]Biały ekran śmierci[/h3]
@@ -27,5 +27,5 @@ Jeśli członkowie społeczności z wykształceniem i doświadczeniem w zakresie
Następnie musisz zaczekać. Jeśli jest to poważny problem, może zostać szybko rozwiązany, ale nikt nie jest odpowiedzialny za naprawianie błędów. Jeśli problem utrzymuje się bez rozwiązania, poświęć trochę czasu na zbadanie samemu problemu. Zapytaj o wszystko, czego nie rozumiesz a co jest związane z tym problemem. Dowiesz się więcej o tym, jak działa oprogramowanie i prawdopodobnie dowiesz się, dlaczego teraz nie działa. Ostatecznie to ktoś w społeczności ma zamiar to naprawić, a ty jesteś członkiem społeczności. Tak właśnie działa proces Open Source.
Inne osoby pracujące nad rozwiązaniem problemu mogą potrzebować dowiedzieć się więcej, więc odrób swoją pracę domową i udokumentuj, co się dzieje i wszystko, czego próbowałeś. Nie mów "Zrobiłem xyz i to nie działa". To nam nic nie mówi. Powiedz nam dokładnie, jakie kroki podjąłeś i jaki był rezultat, a także co się w rezultacie wydarzyło. Jaką stronę (URL) przeglądałeś lub jaki formularz wypełniałeś? Jeśli były jakieś komunikaty o błędach, nie mów "wystąpił komunikat o błędzie". Powiedz nam dokładnie, o czym była wiadomość. Powiedz nam również, z jakiego huba korzystasz, jakiej wersji oprogramowania używasz i wszelkie inne szczegóły, które mogą być unikalne na temat konfiguracji Twojej witryny. Rozumie się, że możesz chcieć zachować prywatność niektórych informacji i swoich połączeń, jednak jeśli nie chcesz udostępniać informacji potrzebnych innym osobom do odtworzenia i rozwiązania problemu, może on nie zostać naprawiony.
Inne osoby pracujące nad rozwiązaniem problemu mogą potrzebować dowiedzieć się więcej, więc odrób swoją pracę domową i udokumentuj, co się dzieje i wszystko, czego próbowałeś. Nie mów "Zrobiłem xyz i to nie działa". To nam nic nie mówi. Powiedz nam dokładnie, jakie kroki podjąłeś i jaki był rezultat, a także co się w rezultacie wydarzyło. Jaką stronę (URL) przeglądałeś lub jaki formularz wypełniałeś? Jeśli były jakieś komunikaty o błędach, nie mów "wystąpił komunikat o błędzie". Powiedz nam dokładnie, o czym była wiadomość. Powiedz nam również, z jakiego węzła korzystasz, jakiej wersji oprogramowania używasz i wszelkie inne szczegóły, które mogą być unikalne na temat konfiguracji Twojej witryny. Rozumie się, że możesz chcieć zachować prywatność niektórych informacji i swoich połączeń, jednak jeśli nie chcesz udostępniać informacji potrzebnych innym osobom do odtworzenia i rozwiązania problemu, może on nie zostać naprawiony.

View File

@@ -1,6 +1,6 @@
[b]Sprawdzanie wykorzystania limitu konta (wykorzystanie limitów usług)[/b]
Na Twoim hubie mogą zostać zaimplementowane limity klas usług, przypisujące ograniczenia do całkowitego rozmiaru miejsca na plików i zdjęci, ilosci kanałów i postów najwyższego poziomu, jakie może utworzyć właściciel konta dla określonego poziomu usług i inne ograniczenia.
Na Twoim węźle mogą zostać zaimplementowane limity klas usług, przypisujące ograniczenia do całkowitego rozmiaru miejsca na plików i zdjęci, ilosci kanałów i wpisów najwyższego poziomu, jakie może utworzyć właściciel konta dla określonego poziomu usług i inne ograniczenia.
Oto, jak możesz szybko sprawdzić, ile z przydzielonego limitu aktualnie używasz:

93
doc/pl/directories.bb Normal file
View File

@@ -0,0 +1,93 @@
[h3]Konfiguracja katalogu[/h3]
Katalogi w $Projectname służą do wyszukiwania i lokalizowania członków w całej sieci Zot. również używane do przechowywania i wysyłania zapytań o "oceny" członków i serwisów. Katalogi dystrybuowane i dublowane, więc awaria jednej z nich nie spowoduje wyłączenia lub zakłócenia całej sieci.
[b]Standardowa konfiguracja[/b]
Nowe serwisy działają zaraz po uruchomieniu jako klienty katalogi będą, podczas pierwszego uruchomienia, automatycznie wybierać serwery katalogowe z zakodowanej listy. Możesz przeanalizować lub zmienić cechę za pomocą polecenia:
[code]
util/config system directory_server
[/code]
Aby ustawić inny serwer katalogowy:
[code]
util/config system directory_server https://newdirectory.something
[/code]
[b]Konfiguracja autonomicznego sewera[/b]
Niektóre serwisy mogą chcieć działać w trybie "autonomicznym" i nie łączyć się z żądnymi zewnętrznymi serwerami katalogami. Jest to przydatne w przypadku serwisów izolowanych ("poza siecią") i serwisów testowych, ale może być również przydatne dla małych organizacji, które nie chcą łączyć się z innymi serwisami w sieci.
Aby to skonfigurować, poszukaj w swoim pliku .htconfig.php następującego tekstu i odpowiednio ustaw konfigurację.
[code]
// Configure how we communicate with directory servers.
// DIRECTORY_MODE_NORMAL = directory client, we will find a directory
// DIRECTORY_MODE_SECONDARY = caching directory or mirror
// DIRECTORY_MODE_PRIMARY = main directory server
// DIRECTORY_MODE_STANDALONE = "off the grid" or private directory services
App::$config['system']['directory_mode'] = DIRECTORY_MODE_STANDALONE;
[/code]
[b]Konfiguracja serwera pomocniczego[/b]
Można także skonfigurować swoją witrynę jako serwer pomocniczy. Działa to jako kopia lustrzana katalogu głównego i umożliwia podział obciążenia między dostępne serwery. Istnieje bardzo niewielka różnica funkcjonalna między podstawowym i pomocniczym serwerem, jednak może istnieć tylko jeden główny serwer katalogowy na dziedzinę (dziedziny omówione w dalszej części tego dokumentu).
Przed zdecydowaniem się na obsługę serwera katalogowego należy pamiętać, że trzeba być aktywnym członkiem sieci oraz mieć zasoby i czas do zarządzania tymi usługami. Zwykle nie wymaga to specjalnego zarządzania, ale niezbędna jest większa stabilność, ponieważ utrata serwera katalogów może powodować problemy z klientami katalogów, którzy od niego zależni.
[b]Konfiguracja serwera katalogowego[/b]
Jeśli serwer katalogowy wskazuje, że nie jest już serwerem katalogów, powinno to zostać wykryte przez oprogramowanie i konfiguracja tego serwera zostanie usunięta (wygaszona). Jeśli przejdzie w tryb offline na stałe bez ostrzeżenia, będziesz wiedzieć tylko wtedy, gdy członkowie witryny zgłoszą, że katalogi niedostępne. Obecnie administrator witryny może to naprawić tylko ręcznie, wybierając nowy katalog i wykonując polecenie:
[code]
util/config system directory_server https://newdirectory.something
[/code]
Mamy nadzieję, że w przyszłości będzie to konfigurowane w polu do wyboru w panelu administracyjnego serwisu.
[h2]Dziedziny katalogów[/h2]
Duże organizacje mogą chcieć używać "dziedzin" katalogów zamiast pojedynczego samodzielnego katalogu. Dziedzina standardowa i domyślna jest znana jako RED_GLOBAL. Tworząc nową dziedzinę, organizacja ma możliwość tworzenia własnej hierarchii serwerów głównych i pomocniczych oraz klientów.
[code]
util/config system directory_realm MY_REALM
[/code]
Twoja dziedzina musi mieć katalog główny. Utwórz to najpierw. Następnie ustaw samą dziedzinę we wszystkich serwisach w dziedzinie katalogu (serwerach i klientach).
Możesz także podać "dziedzinę podrzędną", która działa niezależnie od dziedziny RED_GLOBAL (lub dowolnej innej dziedziny), ale umożliwia wzajemne członkostwo i pewne możliwości wyszukiwania członków w całej przestrzeni katalogu. To przeszło tylko lekkie testy, więc przygotuj się na pomoc i naprawienie wszelkich problemów, które mogą się pojawić. Dziedzina podrzędna zawiera dziedzinę nadrzędną w nazwie dziedziny.
[code]
util/config system directory_realm RED_GLOBAL:MY_REALM
[/code]
[b]Dostęp do dziedziny[/b]
Można zrobić tak, aby Twoje serwery katalogowe i usługi były używane tylko przez członków Twojej dziedziny. W tym celu trzeba zastosować podawanie tokenu lub hasła, aby uzyskać dostęp do usług katalogowych dziedziny. Ten token nie jest szyfrowany podczas przesyłania, ale jest wystarczający, aby zapobiec przypadkowemu dostępowi do serwerów katalogowych. Dla wszystkich lokacji (klientów i serwerów katalogowych) w dziedzinie należy skonfigurować następujące elementy:
[code]
util/config system realm_token my-secret-realm-password
[/code]
[h2]Katalogi lustrzane[/h2]
Dublowanie odbywa się przy uzyciu dziennika transakcji, które współużytkowane przez serwery katalogowe. W przypadku aktualizacji katalogu i profilu przesyłany jest adres kanału przeprowadzającego aktualizację, a inne serwery katalogów sondują ten kanał u źródła pod kątem zmian. Nie ufamy i nie powinniśmy ufać żadnym informacjom przekazanym nam przez inne serwery katalogowe. Informacje zawsze trzeba sprawdzać u źródła.
Oceny obsługiwane nieco inaczej - zaszyfrowany pakiet (podpisany przez kanał, który utworzył ocenę) jest przesyłany między serwerami. Ten podpis musi zostać zweryfikowany przed zaakceptowaniem oceny. Oceny zawsze publikowane na głównym serwerze katalogów i stamtąd propagowane do wszystkich innych serwerów katalogów. Z tego powodu w dziedzinie może istnieć tylko jeden serwer główny. Jeśli źle skonfigurowana witryna twierdzi, że jest katalogiem głównym, jest ignorowana w dziedzinie RED_GLOBAL. W innych dzidzinach obecnie nie ma takiej ochrony. Należy o tym pamiętać podczas pracy z alternatywnymi dziedzinami.
Nowo utworzone serwery katalogowe nie otrzymują "pełnego zrzutu", ale ze względu na wydajność i minimalne zakłócenia działania innych serwerów w sieci, one powoli przełączane do trybu online. Może minąć nawet miesiąc, zanim nowy pomocniczy serwer katalogowy zapewni pełny widok sieci. Nie dodawaj żadnych serwerów pomocniczych do zakodowanej listy rezerwowych serwerów katalogowych, dopóki nie będą one działać jako katalog przez co najmniej miesiąc.
Wszystkie kanały skonfigurowane do "pingowania" swojego serwera katalogowego raz w miesiącu, w nieco losowych momentach w ciągu miesiąca. Daje to katalogowi możliwość wykrywania martwych kanałów i witryn (przestają one pingować). Następnie oznaczane jako martwe lub nieosiągalne i z czasem będą usuwane z wyników katalogu.
Kanały można skonfigurować tak, aby były "ukryte" w katalogu. Te kanały mogą nadal istnieć w katalogu, ale nie będzie można ich przeszukiwać, a niektóre "wrażliwe" informacje osobiste nie będą w ogóle przechowywane.

View File

@@ -0,0 +1,41 @@
## Kontrola dostępu i uprawnienia
### Prywatne grupy
Włączenie zarządzania i wybóru grup prywatności.
<!-- TODO: full description for Privacy Groups -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 0
### Wiele profili
Możliwość tworzenia wielu profili.
<!-- TODO: full description for Multiple Profiles -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 3
### Kategorie uprawnień
Podawanie alternatywnego ograniczenia uprawnień dla połączeń.
<!-- TODO: full description for Permission Categories -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 2
### Klienty OAuth
Zarządzaj tokenami uwierzytelniającymi dla aplikacji mobilnych i zdalnych.
<!-- TODO: full description for OAuth Clients -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 1
### Tokeny dostępu
Utwórz tokeny dostępu, aby osoby niebędące członkami mogły uzyskać dostęp do treści prywatnych.
<!-- TODO: full description for Access Tokens -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 2

View File

View File

@@ -0,0 +1,64 @@
## Funkcje tworzenia wpisów
### Duże obrazy
Możliwość dołączania do wpisów dużych (1024px) miniatur zdjęć. Jeśli ta opcja nie jest jest włączona, będą uzywane małe miniatury (640 pikseli)
<!-- TODO: full description for Large Photos -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 1
### Źródła kanałów
Automatyczne importowanie zawartośvi kanału z innych kanałów lub źródeł
<!-- TODO: full description for Channel Sources -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 3
### Jeszcze więcej szyfrowania
Zezwalaj na opcjonalne szyfrowanie zawartości *end-to-end* za pomocą wspólnego tajnego klucza
<!-- TODO: full description for Even More Encryption -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 3
### Włącz narzędzia do głosowania
Podaj klasę wpisów, na które inni mogą głosować
<!-- TODO: full description for Enable Voting Tools -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 3
### Wyłączenie komentowania
Zapewnia opcję wyłączenia komentarzy do wpisu
<!-- TODO: full description for Disable Comments -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 2
### Opóźnione wysyłanie
Zezwolenie na publikację wpisów w późniejszym terminie
<!-- TODO: full description for Delayed Posting -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 2
### Wygasanie treści
Usuwanie wpisów i komentarzy albo prywatnych wiadomości w przyszłości.
<!-- TODO: full description for Content Expiration -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 1
### Pomijanie powielonych wpisów i komentarzy
Zapobiega publikowaniu wpisów o identycznej treści zapisanych mniej niż dwie minuty między zgłoszeniami.
<!-- TODO: full description for Suppress Duplicate Posts/Comments -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 1

View File

@@ -0,0 +1,59 @@
[ftset]: /settings/features "Dodatkowe funkcjonalności"
## Sieć i filtrowanie strumienia
### Wyszukiwanie wg daty
> Dostępna na stronie ...
Możliwość wyboru wpisów według zakresów dat.
<!-- TODO: full description for Search by Date -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 1
### Zapisywane wyszukiwanie
> dostępna na stronie [Dodatkowe funkcjonalności] [ftset]
Zapis wyszukiwanego hasła do ponownego wykorzystania
<!-- TODO: full description for Saved Searches -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 2
### Karta "Osobista sieć"
Włącza zakładkę, aby wyświetlać tylko wpisy sieciowe, z którymi uzytkownik miał interakcję.
<!-- TODO: full description for Network Personal Tab -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 1
### Karta "Nowa sieć"
Włącza kartę, aby wyświetlić całą nową aktywność sieciową.
<!-- TODO: full description for Network New Tab -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 2
### Narzędzie zaprzyjaźnienia
Filtruje aktywność strumienia według głębokości relacji.
<!-- TODO: full description for Affinity Tool -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 1
### Sugerowane kanały
Pokazuje sugestie dotyczące znajomych i połączeń.
<!-- TODO: full description for Suggest Channels -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 1
### Filtrowanie połączenia
Filtrowanie przychodzących wpisów na podstawie słów kluczowych lub treści (fraz).
<!-- TODO: full description for Connection Filtering -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 3

View File

@@ -0,0 +1,128 @@
## Funkcje ogólne
### Linki dla nowych członków
Wyświetla skrótowe menu z linkami dla nowych członków.
<!-- TODO: full description for New Member Links -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 1
### Zaawansowane profile
Dodatkowe sekcje profilu i pól wyboru.
<!-- TODO: full description for Advanced Profiles -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 1
### Import/Export profili
Zapisywanie i ładowanie szczegółów profilu ze stronu *sites/channels*
<!-- TODO: full description for Profile Import/Export -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 3
### Strony internetowe
Udostępnienie zarządzania stronami internetowymi na swoim kanale
<!-- TODO: full description for Web Pages -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 3
### Wiki
Dostarcza wiki dla kanału
<!-- TODO: full description for Wiki -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 2
### Prywatne notatki
Udostępnia narzędzie do przechowywania notatek i przypomnień (uwaga: niezaszyfrowane)
<!-- TODO: full description for Private Notes -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 1
### Karty
Tworzenie osobistych kart zadań
<!-- TODO: full description for Cards -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 1
### Artykuły
Tworzenie interaktywnych artykułów
<!-- TODO: full description for Articles -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 1
### Wybór kanału nawigacji
Umożliwienia zmiany kanału bezpośrednio z rozwijanego menu nawigacji
<!-- TODO: full description for Navigation Channel Select -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 3
### Lokalizacja zdjecia
Połączenie z mapą danych lokalizacyjnych zdjęcia, jeśli są dostępne w przesłanym zdjęciu.
<!-- TODO: full description for Photo Location -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 2
### Dostęp do kontrolowanych czatów
Zapewnij pokoje rozmów i usługi czatu z kontrolą dostępu.
<!-- TODO: full description for Access Controlled Chatrooms -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 1
### Inteligentne urodziny
Informowanie o strefie czasowej wydarzeń urodzinowych, jeśli znajomi są rozproszeni po całej globie.
<!-- TODO: full description for Smart Birthdays -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 2
### Wybór strefy czasowej zdarzeń
Umożliwia tworzenie wydarzeń w strefach czasowych innych niż autora kanału.
<!-- TODO: full description for Event Timezone Selection -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 2
### Kanał premium
Pozwala ustawić ograniczenia i warunki łączenia się ze swoim kanałem
<!-- TODO: full description for Premium Channel -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 4
### Zaawansowane przeszukiwanie katalogu
Umożliwia tworzenie złożonych zapytań wyszukiwania w katalogu.
<!-- TODO: full description for Advanced Directory Search -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 4
### Zaawansowane ustawienia motywu i układu
Umożliwia precyzyjne dostosowywanie motywów i układów stron
<!-- TODO: full description for Advanced Theme and Layout Settings -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 4

View File

@@ -0,0 +1,123 @@
[ftset]: /settings/features "Dodatkowe funkcjonalności"
## Dodatkowe możliwości
W $Projectname, oprócz podstawowych ustawień konta i kanałów, każdy użytkownik może również zarządzać dodatkowymi funkcjonalościami związanymi ze swoim kontem i kanałami. Może to robić na stronie [Dodatkowe funkcjonalności] [ftset].
Oto omówienie dostępnych tam opcji, tak jak są wyświetlane na stronie [Dodatkowe funkcjonalności] [ftset]:
<h3 id="calendar_settings">Kalendarz</h3>
Są to opcje, które można dodatkow włączyć dla wszystkich swoich kalendarzy. Można to zmienić indywidualnie w każdym kalendarzu.
<h4>Rozpocznij tydzień kalendarzowy w poniedziałek</h4>
W kalendarzach $Projectname, domyślnie jest to niedziela.
<h4>Wybór strefy czasowej wydarzenia</h4>
Zezwolenie na tworzenie wydarzeń w strefach czasowych innych niż strefa ustawiona dla kanału.
<h3 id="channel_main_page_settings">Strona główna kanału</h3>
Kilka dodatkowych możliwości związanych ze stroną główną kanału.
<h4>Wyszukaj po dacie</h4>
Możliwość wyboru wpisów według zakresów dat
<h4>Chmura tagów</h4>
Udostępnienie osobistej chmury tagów na stronie swojego kanału
<!-- TODO: full description for Tag Cloud -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 2
<h4>Użyj trybu bloga/listy</h4>
Komentarze będą wyświetlane osobno
<h3 id="connections_settings">Połączenia</h3>
Obecnie jest tu tylko ustawienie opcji umożliwiającej filtrowanie strumienia wg słów kluczowych lub treści (fraz).
<h3 id="conversation_settings">Rozmowa</h3>
Kilka dodatkowych opcji rozszerzających obsługę rozmów (i dyskusji).
<h3 id="directory_settings">Katalog</h3>
Dostępna tu opcja zaawansowanego przeszukiawania katalogu może być bardzo użyteczna dla osób chcących dotrzeć do konkretnych informacji publikowanych w sieci Hubzilla.
<h4>Zaawansowane przeszukiwanie katalogu</h4>
Umożliwia tworzenie złożonych zapytań wyszukiwania w katalogu.
<!-- TODO: full description for Advanced Directory Search -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 4
<h3 id="manage_settings">Zarządzanie</h3>
Dostępna tu opcja włącza funkcję zmiany kanału bezpośrednio z rozwijanego menu nawigacji.
<h3 id="network_settings">Sieć</h3>
Znajduje się tu szereg opcji włączających funkcje związane z siecią i strumieniem sieciowym. Przede wszystkim dostępnych jest tu kilka dodatkowych filtrów i inne użyteczne funkcje.
<h4>Filtr wydarzeń</h4>
Możliwość wyświetlania tylko wydarzeń
<h4>Filtr ankiet</h4>
Możliwość wyświetlania tylko ankiet
<h4>Zapisywane wyszukiwanie</h4>
Zapisywanie wyszukiwanych haseł do ponownego wykorzystania
<!-- TODO: full description for Saved Searches -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 2
<h4>Zapisywane foldery</h4>
Możliwość umieszczania wpisów w folderach
<!-- TODO: full description for Saved Folders -->
Wymagany minimalny poziom umiejętności technicznych do korzystania z tej funkcji: 2
<h4>Alternatywna kolejność strumienia</h4>
Możliwość uporządkowania strumienia według daty ostatniego wpisu, daty ostatniego komentarza lub nieprzeczytanych aktywności
<h4>Filtr kontaktów</h4>
Możliwość wyświetlania wpisów autorstwa tylko wybranego kontaktu
<h4>Filtr forów</h4>
Możliwość wyświetlania wpisów tylko z określonego forum
<h4>Filtr wpisów osobistych</h4>
Możliwość wyświetlania tylko tych wpisów, z którymi miało się interakcję
<h4>Użyj trybu bloga/listy</h4>
Komentarze będą wyświetlane osobno
<h3 id="photos_settings">Zdjęcia</h3>
<h4>Lokalizacja zdjecia</h4>
Połączenie z mapą danych lokalizacyjnych zdjęcia, jeśli są dostępne w przesłanym zdjęciu
<!-- TODO: full description for Photo Location -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 2
<h3 id="profiles_settings">Profile</h3>
W tej sekcji zawarte są opcje włączające dodatkowe funkcje dotyczące profilu. Jeśli chcesz i możesz zakładać na swoim koncie wiele profili (i tożsamości), włącz tu opcję "wiele profili".
<h4>Profile zaawansowane</h4>
Dodatkowe sekcje profilu i pól wyborów
<!-- TODO: full description for Advanced Profiles -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 1
<h4>Import/Export profilu</h4>
Zapisywanie i ładowanie szczegółów profilu ze stronu <i>sites/channels</i>.
<!-- TODO: full description for Profile Import/Export -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 3
<h4>Wiele profili</h4>
Umożliwienie tworzenia wielu profili i tożsamości, jeśli parametry konta to dozwalają.
Powszechną praktyka jest limitowanie przydzielonych użytkownikowi zasobów serwera w ramach konta. Ogranicza się nie tylko powierzchnie dyskową ale i też ilość profili i tozsamości, jakie uzytkownik moze utworzyć.
<!-- TODO: full description for Multiple Profiles -->
Wymagany minimalny poziom umiejętności technicznych, aby używać tę funkcję: 3

Some files were not shown because too many files have changed in this diff Show More