Browse Source

Merge branch 'edge' into meteor-1.8

Lauri Ojansivu 6 years ago
parent
commit
4903f3a814

+ 17 - 0
CHANGELOG.md

@@ -1,3 +1,20 @@
+# v2.73 2019-05-14 Wekan release
+
+This release fixes the following bugs with Apache I-CLA:
+
+- [Card count placement and export API functionality back](https://github.com/wekan/wekan/pulls/2406).
+  Thanks to bentiss.
+- [Few fixes for Dockerfile](https://github.com/wekan/wekan/pulls/2407).
+  Thanks to bentiss.
+
+and fixes the following bugs:
+
+- Fixed [#2338](https://github.com/wekan/wekan/issues/2338) -> [Slow opening of big boards with too many archived items](https://github.com/wekan/wekan/pull/2402).
+  If some Wekan users see errors with this, please empty your browser cache.
+  Thanks to nerminator.
+
+Thanks to above GitHub users for their contributions and translators for their translations.
+
 # v2.72 2019-05-13 Wekan release
 
 This release adds the following new features:

+ 5 - 5
Dockerfile

@@ -194,7 +194,7 @@ RUN \
     \
     # Get additional packages
     #mkdir -p /home/wekan/app/packages && \
-    chown wekan --recursive /home/wekan && \
+    #chown wekan:wekan --recursive /home/wekan && \
     # REPOS BELOW ARE INCLUDED TO WEKAN REPO
     #cd /home/wekan/app/packages && \
     #gosu wekan:wekan git clone --depth 1 -b master https://github.com/wekan/flow-router.git kadira-flow-router && \
@@ -212,7 +212,7 @@ RUN \
     gosu wekan:wekan /home/wekan/.meteor/meteor -- help; \
     \
     # extract the OpenAPI specification
-    npm install -g api2html@0.3.0 && \
+    npm install -g api2html@0.3.3 && \
     mkdir -p /home/wekan/python && \
     chown wekan --recursive /home/wekan/python && \
     cd /home/wekan/python && \
@@ -220,9 +220,9 @@ RUN \
     cd /home/wekan/python/esprima-python && \
     python3 setup.py install --record files.txt && \
     cd /home/wekan/app &&\
-    mkdir -p ./public/api && \
-    python3 ./openapi/generate_openapi.py --release $(git describe --tags --abbrev=0) > ./public/api/wekan.yml && \
-    /opt/nodejs/bin/api2html -c ./public/logo-header.png -o ./public/api/wekan.html ./public/api/wekan.yml; \
+    gosu wekan:wekan mkdir -p ./public/api && \
+    gosu wekan:wekan python3 ./openapi/generate_openapi.py --release $(git describe --tags --abbrev=0) > ./public/api/wekan.yml && \
+    gosu wekan:wekan /opt/nodejs/bin/api2html -c ./public/logo-header.png -o ./public/api/wekan.html ./public/api/wekan.yml; \
     # Build app
     cd /home/wekan/app && \
     gosu wekan:wekan /home/wekan/.meteor/meteor add standard-minifier-js && \

+ 1 - 1
Stackerfile.yml

@@ -1,5 +1,5 @@
 appId: wekan-public/apps/77b94f60-dec9-0136-304e-16ff53095928
-appVersion: "v2.72.0"
+appVersion: "v2.73.0"
 files:
   userUploads:
     - README.md

+ 1 - 1
client/components/boards/boardBody.js

@@ -14,7 +14,7 @@ BlazeComponent.extendComponent({
       const currentBoardId = Session.get('currentBoard');
       if (!currentBoardId)
         return;
-      const handle = subManager.subscribe('board', currentBoardId);
+      const handle = subManager.subscribe('board', currentBoardId, false);
       Tracker.nonreactive(() => {
         Tracker.autorun(() => {
           this.isBoardReady.set(handle.ready());

+ 2 - 2
client/components/boards/boardsList.js

@@ -33,12 +33,12 @@ BlazeComponent.extendComponent({
   },
 
   hasOvertimeCards() {
-    subManager.subscribe('board', this.currentData()._id);
+    subManager.subscribe('board', this.currentData()._id, false);
     return this.currentData().hasOvertimeCards();
   },
 
   hasSpentTimeCards() {
-    subManager.subscribe('board', this.currentData()._id);
+    subManager.subscribe('board', this.currentData()._id, false);
     return this.currentData().hasSpentTimeCards();
   },
 

+ 3 - 3
client/components/cards/cardDetails.js

@@ -424,7 +424,7 @@ Template.moveCardPopup.events({
 });
 BlazeComponent.extendComponent({
   onCreated() {
-    subManager.subscribe('board', Session.get('currentBoard'));
+    subManager.subscribe('board', Session.get('currentBoard'), false);
     this.selectedBoardId = new ReactiveVar(Session.get('currentBoard'));
   },
 
@@ -453,7 +453,7 @@ BlazeComponent.extendComponent({
     return [{
       'change .js-select-boards'(evt) {
         this.selectedBoardId.set($(evt.currentTarget).val());
-        subManager.subscribe('board', this.selectedBoardId.get());
+        subManager.subscribe('board', this.selectedBoardId.get(), false);
       },
     }];
   },
@@ -676,7 +676,7 @@ BlazeComponent.extendComponent({
         if (selection === 'none') {
           this.parentBoard.set(null);
         } else {
-          subManager.subscribe('board', $(evt.currentTarget).val());
+          subManager.subscribe('board', $(evt.currentTarget).val(), false);
           this.parentBoard.set(selection);
           list.prop('disabled', false);
         }

+ 4 - 0
client/components/lists/list.styl

@@ -99,6 +99,10 @@
   .highlight
     color: #ce1414
 
+  .cardCount
+    color: #8c8c8c
+    font-size: 0.8em
+
 .list-body
   flex: 1 1 auto
   flex-direction: column

+ 6 - 6
client/components/lists/listBody.js

@@ -348,7 +348,7 @@ BlazeComponent.extendComponent({
 
     this.boardId = Session.get('currentBoard');
     // In order to get current board info
-    subManager.subscribe('board', this.boardId);
+    subManager.subscribe('board', this.boardId, false);
     this.board = Boards.findOne(this.boardId);
     // List where to insert card
     const list = $(Popup._getTopStack().openerElement).closest('.js-list');
@@ -414,7 +414,7 @@ BlazeComponent.extendComponent({
   events() {
     return [{
       'change .js-select-boards'(evt) {
-        subManager.subscribe('board', $(evt.currentTarget).val());
+        subManager.subscribe('board', $(evt.currentTarget).val(), false);
         this.selectedBoardId.set($(evt.currentTarget).val());
       },
       'change .js-select-swimlanes'(evt) {
@@ -500,13 +500,13 @@ BlazeComponent.extendComponent({
     }
     const boardId = board._id;
     // Subscribe to this board
-    subManager.subscribe('board', boardId);
+    subManager.subscribe('board', boardId, false);
     this.selectedBoardId = new ReactiveVar(boardId);
 
     if (!this.isBoardTemplateSearch) {
       this.boardId = Session.get('currentBoard');
       // In order to get current board info
-      subManager.subscribe('board', this.boardId);
+      subManager.subscribe('board', this.boardId, false);
       this.swimlaneId = '';
       // Swimlane where to insert card
       const swimlane = $(Popup._getTopStack().openerElement).parents('.js-swimlane');
@@ -547,7 +547,7 @@ BlazeComponent.extendComponent({
     } else if (this.isBoardTemplateSearch) {
       const boards = board.searchBoards(this.term.get());
       boards.forEach((board) => {
-        subManager.subscribe('board', board.linkedId);
+        subManager.subscribe('board', board.linkedId, false);
       });
       return boards;
     } else {
@@ -558,7 +558,7 @@ BlazeComponent.extendComponent({
   events() {
     return [{
       'change .js-select-boards'(evt) {
-        subManager.subscribe('board', $(evt.currentTarget).val());
+        subManager.subscribe('board', $(evt.currentTarget).val(), false);
         this.selectedBoardId.set($(evt.currentTarget).val());
       },
       'submit .js-search-term-form'(evt) {

+ 1 - 1
client/components/lists/listHeader.jade

@@ -19,7 +19,7 @@ template(name="listHeader")
 
         if showCardsCountForList cards.count
           | 
-          p.quiet.small {{cardsCount}} {{_ 'cards-count'}}
+          span(class="cardCount") {{cardsCount}} {{_ 'cards-count'}}
       if isMiniScreen
         if currentList
           if isWatching

+ 49 - 47
client/components/sidebar/sidebarArchives.jade

@@ -1,54 +1,56 @@
 template(name="archivesSidebar")
-  +basicTabs(tabs=tabs)
-
-   +tabContent(slug="cards")
-    p.quiet
-      a.js-restore-all-cards {{_ 'restore-all'}}
-      | -
-      a.js-delete-all-cards {{_ 'delete-all'}}
-    each archivedCards
-      .minicard-wrapper.js-minicard
-        +minicard(this)
-      if currentUser.isBoardMember
+  if isArchiveReady.get
+    +basicTabs(tabs=tabs)
+      +tabContent(slug="cards")
         p.quiet
-          a.js-restore-card {{_ 'restore'}}
+          a.js-restore-all-cards {{_ 'restore-all'}}
           | -
-          a.js-delete-card {{_ 'delete'}}
-        if cardIsInArchivedList
-          p.quiet.small ({{_ 'warn-list-archived'}})
-    else
-      p.no-items-message {{_ 'no-archived-cards'}}
-
-   +tabContent(slug="lists")
-    p.quiet
-      a.js-restore-all-lists {{_ 'restore-all'}}
-      | -
-      a.js-delete-all-lists {{_ 'delete-all'}}
-    ul.archived-lists
-      each archivedLists
-        li.archived-lists-item
-          = title
+          a.js-delete-all-cards {{_ 'delete-all'}}
+        each archivedCards
+          .minicard-wrapper.js-minicard
+            +minicard(this)
           if currentUser.isBoardMember
             p.quiet
-              a.js-restore-list {{_ 'restore'}}
+              a.js-restore-card {{_ 'restore'}}
               | -
-              a.js-delete-list {{_ 'delete'}}
-      else
-        li.no-items-message {{_ 'no-archived-lists'}}
+              a.js-delete-card {{_ 'delete'}}
+            if cardIsInArchivedList
+              p.quiet.small ({{_ 'warn-list-archived'}})
+        else
+          p.no-items-message {{_ 'no-archived-cards'}}
 
-   +tabContent(slug="swimlanes")
-    p.quiet
-      a.js-restore-all-swimlanes {{_ 'restore-all'}}
-      | -
-      a.js-delete-all-swimlanes {{_ 'delete-all'}}
-    ul.archived-lists
-      each archivedSwimlanes
-        li.archived-lists-item
-          = title
-          if currentUser.isBoardMember
-            p.quiet
-              a.js-restore-swimlane {{_ 'restore'}}
-              | -
-              a.js-delete-swimlane {{_ 'delete'}}
-      else
-        li.no-items-message {{_ 'no-archived-swimlanes'}}
+      +tabContent(slug="lists")
+        p.quiet
+          a.js-restore-all-lists {{_ 'restore-all'}}
+          | -
+          a.js-delete-all-lists {{_ 'delete-all'}}
+        ul.archived-lists
+          each archivedLists
+            li.archived-lists-item
+              = title
+              if currentUser.isBoardMember
+                p.quiet
+                  a.js-restore-list {{_ 'restore'}}
+                  | -
+                  a.js-delete-list {{_ 'delete'}}
+          else
+            li.no-items-message {{_ 'no-archived-lists'}}
+
+      +tabContent(slug="swimlanes")
+        p.quiet
+          a.js-restore-all-swimlanes {{_ 'restore-all'}}
+          | -
+          a.js-delete-all-swimlanes {{_ 'delete-all'}}
+        ul.archived-lists
+          each archivedSwimlanes
+            li.archived-lists-item
+              = title
+              if currentUser.isBoardMember
+                p.quiet
+                  a.js-restore-swimlane {{_ 'restore'}}
+                  | -
+                  a.js-delete-swimlane {{_ 'delete'}}
+          else
+            li.no-items-message {{_ 'no-archived-swimlanes'}}
+  else
+    +spinner

+ 22 - 0
client/components/sidebar/sidebarArchives.js

@@ -1,4 +1,26 @@
+const subManager = new SubsManager();
+
 BlazeComponent.extendComponent({
+  onCreated() {
+    this.isArchiveReady = new ReactiveVar(false);
+
+    // The pattern we use to manually handle data loading is described here:
+    // https://kadira.io/academy/meteor-routing-guide/content/subscriptions-and-data-management/using-subs-manager
+    // XXX The boardId should be readed from some sort the component "props",
+    // unfortunatly, Blaze doesn't have this notion.
+    this.autorun(() => {
+      const currentBoardId = Session.get('currentBoard');
+      if (!currentBoardId)
+        return;
+      const handle = subManager.subscribe('board', currentBoardId, true);
+      Tracker.nonreactive(() => {
+        Tracker.autorun(() => {
+          this.isArchiveReady.set( handle.ready() );
+        });
+      });
+    });
+  },
+
   tabs() {
     return [
       { name: TAPi18n.__('cards'), slug: 'cards' },

+ 70 - 70
i18n/fi.i18n.json

@@ -83,7 +83,7 @@
     "added": "Lisätty",
     "addMemberPopup-title": "Jäsenet",
     "admin": "Ylläpitäjä",
-    "admin-desc": "Voi nähfä ja muokata kortteja, poistaa jäseniä, ja muuttaa taulun asetuksia.",
+    "admin-desc": "Voi nähdä ja muokata kortteja, poistaa jäseniä, ja muuttaa taulun asetuksia.",
     "admin-announcement": "Ilmoitus",
     "admin-announcement-active": "Aktiivinen järjestelmänlaajuinen ilmoitus",
     "admin-announcement-title": "Ilmoitus ylläpitäjältä",
@@ -103,7 +103,7 @@
     "archived-items": "Arkisto",
     "archived-boards": "Taulut Arkistossa",
     "restore-board": "Palauta taulu",
-    "no-archived-boards": "Ei tauluja Arkistossa",
+    "no-archived-boards": "Ei tauluja Arkistossa.",
     "archives": "Arkisto",
     "template": "Malli",
     "templates": "Mallit",
@@ -114,7 +114,7 @@
     "attachmentDeletePopup-title": "Poista liitetiedosto?",
     "attachments": "Liitetiedostot",
     "auto-watch": "Automaattisesti seuraa tauluja kun ne on luotu",
-    "avatar-too-big": "Profiilikuva on liian suuri (70KB maksimi)",
+    "avatar-too-big": "Profiilikuva on liian suuri (enintään 70 kt)",
     "back": "Takaisin",
     "board-change-color": "Muokkaa väriä",
     "board-nb-stars": "%s tähteä",
@@ -125,9 +125,9 @@
     "boardChangeTitlePopup-title": "Nimeä taulu uudelleen",
     "boardChangeVisibilityPopup-title": "Muokkaa näkyvyyttä",
     "boardChangeWatchPopup-title": "Muokkaa seuraamista",
-    "boardMenuPopup-title": "Taulu asetukset",
+    "boardMenuPopup-title": "Tauluasetukset",
     "boards": "Taulut",
-    "board-view": "Taulu näkymä",
+    "board-view": "Taulunäkymä",
     "board-view-cal": "Kalenteri",
     "board-view-swimlanes": "Swimlanet",
     "board-view-lists": "Listat",
@@ -136,8 +136,8 @@
     "card-archived": "Tämä kortti on siirretty Arkistoon.",
     "board-archived": "Tämä taulu on siirretty Arkistoon.",
     "card-comments-title": "Tässä kortissa on %s kommenttia.",
-    "card-delete-notice": "Poistaminen on lopullista. Menetät kaikki toimet jotka on liitetty tähän korttiin.",
-    "card-delete-pop": "Kaikki toimet poistetaan toimintasyötteestä ja et tule pystymään uudelleenavaamaan korttia. Tätä ei voi peruuttaa.",
+    "card-delete-notice": "Poistaminen on lopullista. Menetät kaikki tähän korttiin liitetyt toimet.",
+    "card-delete-pop": "Kaikki toimet poistetaan toimintasyötteestä, etkä pysty avata korttia uudelleen. Tätä ei voi peruuttaa.",
     "card-delete-suggest-archive": "Voit siirtää kortin Arkistoon poistaaksesi sen taululta ja säilyttääksesi toimintalokin.",
     "card-due": "Erääntyy",
     "card-due-on": "Erääntyy",
@@ -154,14 +154,14 @@
     "cardCustomField-datePopup-title": "Muokkaa päivää",
     "cardCustomFieldsPopup-title": "Muokkaa mukautettuja kenttiä",
     "cardDeletePopup-title": "Poista kortti?",
-    "cardDetailsActionsPopup-title": "Kortti toimet",
+    "cardDetailsActionsPopup-title": "Korttitoimet",
     "cardLabelsPopup-title": "Tunnisteet",
     "cardMembersPopup-title": "Jäsenet",
     "cardMorePopup-title": "Lisää",
     "cardTemplatePopup-title": "Luo malli",
     "cards": "Kortit",
     "cards-count": "korttia",
-    "casSignIn": "CAS kirjautuminen",
+    "casSignIn": "CAS-kirjautuminen",
     "cardType-card": "Kortti",
     "cardType-linkedCard": "Linkitetty kortti",
     "cardType-linkedBoard": "Linkitetty taulu",
@@ -182,7 +182,7 @@
     "clipboard": "Leikepöytä tai raahaa ja pudota",
     "close": "Sulje",
     "close-board": "Sulje taulu",
-    "close-board-pop": "Voit palauttaa taulun klikkaamalla “Arkisto” painiketta taululistan yläpalkista.",
+    "close-board-pop": "Voit palauttaa taulun klikkaamalla “Arkisto”-painiketta taululistan yläpalkista.",
     "color-black": "musta",
     "color-blue": "sininen",
     "color-crimson": "karmiininpunainen",
@@ -216,14 +216,14 @@
     "no-comments": "Ei kommentteja",
     "no-comments-desc": "Ei voi nähdä kommentteja ja toimintaa.",
     "computer": "Tietokone",
-    "confirm-subtask-delete-dialog": "Oletko varma että haluat poistaa alitehtävän?",
-    "confirm-checklist-delete-dialog": "Oletko varma että haluat poistaa tarkistuslistan?",
+    "confirm-subtask-delete-dialog": "Haluatko varmasti poistaa alitehtävän?",
+    "confirm-checklist-delete-dialog": "Haluatko varmasti poistaa tarkistuslistan?",
     "copy-card-link-to-clipboard": "Kopioi kortin linkki leikepöydälle",
     "linkCardPopup-title": "Linkitä kortti",
     "searchElementPopup-title": "Etsi",
     "copyCardPopup-title": "Kopioi kortti",
     "copyChecklistToManyCardsPopup-title": "Kopioi tarkistuslistan malli monille korteille",
-    "copyChecklistToManyCardsPopup-instructions": "Kohde korttien otsikot ja kuvaukset JSON muodossa",
+    "copyChecklistToManyCardsPopup-instructions": "Kohde korttien otsikot ja kuvaukset JSON-muodossa",
     "copyChecklistToManyCardsPopup-format": "[ {\"title\": \"Ensimmäisen kortin otsikko\", \"description\":\"Ensimmäisen kortin kuvaus\"}, {\"title\":\"Toisen kortin otsikko\",\"description\":\"Toisen kortin kuvaus\"},{\"title\":\"Viimeisen kortin otsikko\",\"description\":\"Viimeisen kortin kuvaus\"} ]",
     "create": "Luo",
     "createBoardPopup-title": "Luo taulu",
@@ -237,7 +237,7 @@
     "custom-field-date": "Päivämäärä",
     "custom-field-dropdown": "Pudotusvalikko",
     "custom-field-dropdown-none": "(ei mitään)",
-    "custom-field-dropdown-options": "Luettelon vaihtoehdot",
+    "custom-field-dropdown-options": "Listan vaihtoehdot",
     "custom-field-dropdown-options-placeholder": "Paina Enter lisätäksesi lisää vaihtoehtoja",
     "custom-field-dropdown-unknown": "(tuntematon)",
     "custom-field-number": "Numero",
@@ -245,13 +245,13 @@
     "custom-fields": "Mukautetut kentät",
     "date": "Päivämäärä",
     "decline": "Kieltäydy",
-    "default-avatar": "Oletus profiilikuva",
+    "default-avatar": "Oletusprofiilikuva",
     "delete": "Poista",
     "deleteCustomFieldPopup-title": "Poista mukautettu kenttä?",
     "deleteLabelPopup-title": "Poista tunniste?",
     "description": "Kuvaus",
-    "disambiguateMultiLabelPopup-title": "Yksikäsitteistä tunniste toiminta",
-    "disambiguateMultiMemberPopup-title": "Yksikäsitteistä jäsen toiminta",
+    "disambiguateMultiLabelPopup-title": "Yksikäsitteistä tunnistetoiminta",
+    "disambiguateMultiMemberPopup-title": "Yksikäsitteistä jäsentoiminta",
     "discard": "Hylkää",
     "done": "Valmis",
     "download": "Lataa",
@@ -259,7 +259,7 @@
     "edit-avatar": "Muokkaa profiilikuvaa",
     "edit-profile": "Muokkaa profiilia",
     "edit-wip-limit": "Muokkaa WIP-rajaa",
-    "soft-wip-limit": "Pehmeä WIP raja",
+    "soft-wip-limit": "Pehmeä WIP-raja",
     "editCardStartDatePopup-title": "Muokkaa aloituspäivää",
     "editCardDueDatePopup-title": "Muokkaa eräpäivää",
     "editCustomFieldPopup-title": "Muokkaa kenttää",
@@ -268,25 +268,25 @@
     "editNotificationPopup-title": "Muokkaa ilmoituksia",
     "editProfilePopup-title": "Muokkaa profiilia",
     "email": "Sähköposti",
-    "email-enrollAccount-subject": "An account created for you on __siteName__",
-    "email-enrollAccount-text": "Hei __user__,\n\nAlkaaksesi käyttämään palvelua, klikkaa allaolevaa linkkiä.\n\n__url__\n\nKiitos.",
+    "email-enrollAccount-subject": "Sinulle on luotu tili palveluun __siteName__",
+    "email-enrollAccount-text": "Hei __user__,\n\nKlikkaa alla olevaa linkkiä aloittaaksesi palvelun käytön.\n\n__url__\n\nKiitos.",
     "email-fail": "Sähköpostin lähettäminen epäonnistui",
     "email-fail-text": "Virhe yrittäessä lähettää sähköpostia",
     "email-invalid": "Virheellinen sähköposti",
     "email-invite": "Kutsu sähköpostilla",
     "email-invite-subject": "__inviter__ lähetti sinulle kutsun",
-    "email-invite-text": "Hyvä __user__,\n\n__inviter__ kutsuu sinut liittymään taululle \"__board__\" yhteistyötä varten.\n\nOle hyvä ja seuraa allaolevaa linkkiä:\n\n__url__\n\nKiitos.",
-    "email-resetPassword-subject": "Reset your password on __siteName__",
-    "email-resetPassword-text": "Hei __user__,\n\nNollataksesi salasanasi, klikkaa allaolevaa linkkiä.\n\n__url__\n\nKiitos.",
+    "email-invite-text": "Hyvä __user__,\n\n__inviter__ kutsuu sinut liittymään taululle \"__board__\" yhteistyötä varten.\n\nOle hyvä ja seuraa alla olevaa linkkiä:\n\n__url__\n\nKiitos.",
+    "email-resetPassword-subject": "Nollaa salasanasi palvelussa __siteName__",
+    "email-resetPassword-text": "Hei __user__,\n\nNollataksesi salasanasi, klikkaa alla olevaa linkkiä.\n\n__url__\n\nKiitos.",
     "email-sent": "Sähköposti lähetetty",
     "email-verifyEmail-subject": "Varmista sähköpostiosoitteesi osoitteessa __url__",
-    "email-verifyEmail-text": "Hei __user__,\n\nvahvistaaksesi sähköpostiosoitteesi, klikkaa allaolevaa linkkiä.\n\n__url__\n\nKiitos.",
+    "email-verifyEmail-text": "Hei __user__,\n\nvahvistaaksesi sähköpostiosoitteesi, klikkaa alla olevaa linkkiä.\n\n__url__\n\nKiitos.",
     "enable-wip-limit": "Ota käyttöön WIP-raja",
-    "error-board-doesNotExist": "Tämä taulu ei ole olemassa",
+    "error-board-doesNotExist": "Tätä taulua ei ole olemassa",
     "error-board-notAdmin": "Tehdäksesi tämän sinun täytyy olla tämän taulun ylläpitäjä",
     "error-board-notAMember": "Tehdäksesi tämän sinun täytyy olla tämän taulun jäsen",
-    "error-json-malformed": "Tekstisi ei ole kelvollisessa JSON muodossa",
-    "error-json-schema": "JSON tietosi ei sisällä oikeaa tietoa oikeassa muodossa",
+    "error-json-malformed": "Tekstisi ei ole kelvollisessa JSON-muodossa",
+    "error-json-schema": "JSON-tietosi ei sisällä oikeaa tietoa oikeassa muodossa",
     "error-list-doesNotExist": "Tätä listaa ei ole olemassa",
     "error-user-doesNotExist": "Tätä käyttäjää ei ole olemassa",
     "error-user-notAllowSelf": "Et voi kutsua itseäsi",
@@ -316,14 +316,14 @@
     "import-board-c": "Tuo taulu",
     "import-board-title-trello": "Tuo taulu Trellosta",
     "import-board-title-wekan": "Tuo taulu edellisestä viennistä",
-    "import-sandstorm-backup-warning": "Älä poista tietoja joita toit alkuperäisestä viennistä tai Trellosta ennenkuin tarkistat onnistuuko sulkea ja avata tämä jyvä uudelleen, vai näkyykö Board not found virhe, joka tarkoittaa tietojen häviämistä.",
-    "import-sandstorm-warning": "Tuotu taulu poistaa kaikki olemassaolevan taulun tiedot ja korvaa ne tuodulla taululla.",
+    "import-sandstorm-backup-warning": "Älä poista tietoja joita toit alkuperäisestä viennistä tai Trellosta ennen kuin tarkistat onnistuuko sulkea ja avata tämä jyvä uudelleen, vai näkyykö Board not found -virhe, joka tarkoittaa tietojen häviämistä.",
+    "import-sandstorm-warning": "Tuotu taulu poistaa kaikki olemassa olevan taulun tiedot ja korvaa ne tuodulla taululla.",
     "from-trello": "Trellosta",
     "from-wekan": "Edellisestä viennistä",
-    "import-board-instruction-trello": "Trello taulullasi, mene 'Menu', sitten 'More', 'Print and Export', 'Export JSON', ja kopioi tuloksena saamasi teksti",
+    "import-board-instruction-trello": "Mene Trello-taulullasi 'Menu', sitten 'More', 'Print and Export', 'Export JSON', ja kopioi tuloksena saamasi teksti",
     "import-board-instruction-wekan": "Taulullasi, mene 'Valikko', sitten 'Vie taulu', ja kopioi teksti ladatusta tiedostosta.",
     "import-board-instruction-about-errors": "Jos virheitä tulee taulua tuotaessa, joskus tuonti silti toimii, ja taulu on Kaikki taulut sivulla.",
-    "import-json-placeholder": "Liitä kelvollinen JSON tietosi tähän",
+    "import-json-placeholder": "Liitä kelvollinen JSON-tietosi tähän",
     "import-map-members": "Vastaavat jäsenet",
     "import-members-map": "Tuomallasi taululla on muutamia jäseniä. Ole hyvä ja valitse tuomiasi jäseniä vastaavat käyttäjäsi",
     "import-show-user-mapping": "Tarkasta vastaavat jäsenet",
@@ -345,17 +345,17 @@
     "last-admin-desc": "Et voi vaihtaa rooleja koska täytyy olla olemassa ainakin yksi ylläpitäjä.",
     "leave-board": "Jää pois taululta",
     "leave-board-pop": "Haluatko varmasti poistua taululta __boardTitle__? Sinut poistetaan kaikista tämän taulun korteista.",
-    "leaveBoardPopup-title": "Jää pois taululta ?",
+    "leaveBoardPopup-title": "Poistu taululta?",
     "link-card": "Linkki tähän korttiin",
     "list-archive-cards": "Siirrä kaikki tämän listan kortit Arkistoon",
     "list-archive-cards-pop": "Tämä poistaa kaikki tämän listan kortit taululta. Nähdäksesi Arkistossa olevat kortit ja tuodaksesi ne takaisin taululle, klikkaa “Valikko” > “Arkisto”.",
     "list-move-cards": "Siirrä kaikki kortit tässä listassa",
     "list-select-cards": "Valitse kaikki kortit tässä listassa",
     "set-color-list": "Aseta väri",
-    "listActionPopup-title": "Listaa toimet",
-    "swimlaneActionPopup-title": "Swimlane toimet",
+    "listActionPopup-title": "Listatoimet",
+    "swimlaneActionPopup-title": "Swimlane-toimet",
     "swimlaneAddPopup-title": "Lisää Swimlane alle",
-    "listImportCardPopup-title": "Tuo Trello kortti",
+    "listImportCardPopup-title": "Tuo Trello-kortti",
     "listMorePopup-title": "Lisää",
     "link-list": "Linkki tähän listaan",
     "list-delete-pop": "Kaikki toimet poistetaan toimintasyötteestä ja listan poistaminen on lopullista. Tätä ei pysty peruuttamaan.",
@@ -365,7 +365,7 @@
     "log-out": "Kirjaudu ulos",
     "log-in": "Kirjaudu sisään",
     "loginPopup-title": "Kirjaudu sisään",
-    "memberMenuPopup-title": "Jäsen asetukset",
+    "memberMenuPopup-title": "Jäsenasetukset",
     "members": "Jäsenet",
     "menu": "Valikko",
     "move-selection": "Siirrä valinta",
@@ -390,7 +390,7 @@
     "notify-watch": "Vastaanota päivityksiä kaikilta tauluilta, listoilta tai korteilta joita seuraat.",
     "optional": "valinnainen",
     "or": "tai",
-    "page-maybe-private": "Tämä sivu voi olla yksityinen. Voit ehkä pystyä näkemään sen <a href='%s'>kirjautumalla sisään</a>.",
+    "page-maybe-private": "Tämä sivu voi olla yksityinen. Saatat nähdä sen <a href='%s'>kirjautumalla sisään</a>.",
     "page-not-found": "Sivua ei löytynyt.",
     "password": "Salasana",
     "paste-or-dragdrop": "liittääksesi, tai vedä & pudota kuvatiedosto siihen (vain kuva)",
@@ -407,7 +407,7 @@
     "remove-cover": "Poista kansi",
     "remove-from-board": "Poista taululta",
     "remove-label": "Poista tunniste",
-    "listDeletePopup-title": "Poista lista ?",
+    "listDeletePopup-title": "Poista lista?",
     "remove-member": "Poista jäsen",
     "remove-member-from-card": "Poista kortilta",
     "remove-member-pop": "Poista __name__ (__username__) taululta __boardTitle__? Jäsen poistetaan kaikilta taulun korteilta. Heille lähetetään ilmoitus.",
@@ -419,7 +419,7 @@
     "search": "Etsi",
     "rules": "Säännöt",
     "search-cards": "Etsi korttien otsikoista ja kuvauksista tällä taululla",
-    "search-example": "Teksti jota etsitään?",
+    "search-example": "Etsittävä teksti?",
     "select-color": "Valitse väri",
     "set-wip-limit-value": "Aseta tämän listan tehtävien enimmäismäärä",
     "setWipLimitPopup-title": "Aseta WIP-raja",
@@ -429,9 +429,9 @@
     "shortcut-clear-filters": "Poista kaikki suodattimet",
     "shortcut-close-dialog": "Sulje valintaikkuna",
     "shortcut-filter-my-cards": "Suodata korttini",
-    "shortcut-show-shortcuts": "Tuo esiin tämä pikavalinta lista",
-    "shortcut-toggle-filterbar": "Muokkaa suodatus sivupalkin näkyvyyttä",
-    "shortcut-toggle-sidebar": "Muokkaa taulu sivupalkin näkyvyyttä",
+    "shortcut-show-shortcuts": "Tuo esiin tämä pikavalintalista",
+    "shortcut-toggle-filterbar": "Muokkaa suodatussivupalkin näkyvyyttä",
+    "shortcut-toggle-sidebar": "Muokkaa taulusivupalkin näkyvyyttä",
     "show-cards-minimum-count": "Näytä korttien lukumäärä jos lista sisältää enemmän kuin",
     "sidebar-open": "Avaa sivupalkki",
     "sidebar-close": "Sulje sivupalkki",
@@ -446,8 +446,8 @@
     "spent-time-hours": "Käytetty aika (tuntia)",
     "overtime-hours": "Ylityö (tuntia)",
     "overtime": "Ylityö",
-    "has-overtime-cards": "Sisältää ylityö kortteja",
-    "has-spenttime-cards": "Sisältää käytetty aika kortteja",
+    "has-overtime-cards": "Sisältää ylityökortteja",
+    "has-spenttime-cards": "Sisältää käytetty aika -kortteja",
     "time": "Aika",
     "title": "Otsikko",
     "tracking": "Ilmoitukset",
@@ -465,13 +465,13 @@
     "watch": "Seuraa",
     "watching": "Seurataan",
     "watching-info": "Sinulle ilmoitetaan tämän taulun muutoksista",
-    "welcome-board": "Tervetuloa taulu",
+    "welcome-board": "Tervetuloa-taulu",
     "welcome-swimlane": "Merkkipaalu 1",
     "welcome-list1": "Perusasiat",
     "welcome-list2": "Edistynyt",
-    "card-templates-swimlane": "Kortti mallit",
-    "list-templates-swimlane": "Lista mallit",
-    "board-templates-swimlane": "Taulu mallit",
+    "card-templates-swimlane": "Korttimallit",
+    "list-templates-swimlane": "Listamallit",
+    "board-templates-swimlane": "Taulumallit",
     "what-to-do": "Mitä haluat tehdä?",
     "wipLimitErrorPopup-title": "Virheellinen WIP-raja",
     "wipLimitErrorPopup-dialog-pt1": "Tässä listassa olevien tehtävien määrä on korkeampi kuin asettamasi WIP-raja.",
@@ -480,36 +480,36 @@
     "settings": "Asetukset",
     "people": "Ihmiset",
     "registration": "Rekisteröinti",
-    "disable-self-registration": "Poista käytöstä itse-rekisteröityminen",
+    "disable-self-registration": "Poista käytöstä itserekisteröityminen",
     "invite": "Kutsu",
     "invite-people": "Kutsu ihmisiä",
     "to-boards": "Taulu(i)lle",
     "email-addresses": "Sähköpostiosoite",
-    "smtp-host-description": "SMTP palvelimen osoite jolla sähköpostit lähetetään.",
-    "smtp-port-description": "Portti jota STMP palvelimesi käyttää lähteville sähköposteille.",
-    "smtp-tls-description": "Ota käyttöön TLS tuki SMTP palvelimelle",
-    "smtp-host": "SMTP isäntä",
-    "smtp-port": "SMTP portti",
+    "smtp-host-description": "SMTP-palvelimen osoite jolla sähköpostit lähetetään.",
+    "smtp-port-description": "STMP-palvelimesi käyttämä lähteville sähköposteille tarkoitettu portti.",
+    "smtp-tls-description": "Ota käyttöön TLS-tuki SMTP-palvelimelle",
+    "smtp-host": "SMTP-isäntä",
+    "smtp-port": "SMTP-portti",
     "smtp-username": "Käyttäjätunnus",
     "smtp-password": "Salasana",
-    "smtp-tls": "TLS tuki",
+    "smtp-tls": "TLS-tuki",
     "send-from": "Lähettäjä",
-    "send-smtp-test": "Lähetä testi sähköposti itsellesi",
+    "send-smtp-test": "Lähetä testisähköposti itsellesi",
     "invitation-code": "Kutsukoodi",
     "email-invite-register-subject": "__inviter__ lähetti sinulle kutsun",
-    "email-invite-register-text": "Hei __user__,\n\n__inviter__ kutsuu sinut mukaan kanban taulun käyttöön.\n\nOle hyvä ja seuraa allaolevaa linkkiä:\n__url__\n\nJa kutsukoodisi on: __icode__\n\nKiitos.",
-    "email-smtp-test-subject": "SMTP testi sähköposti",
+    "email-invite-register-text": "Hei __user__,\n\n__inviter__ kutsuu sinut mukaan kanban-taulun käyttöön.\n\nOle hyvä ja seuraa alla olevaa linkkiä:\n__url__\n\nKutsukoodisi on: __icode__\n\nKiitos.",
+    "email-smtp-test-subject": "SMTP-testisähköposti",
     "email-smtp-test-text": "Olet onnistuneesti lähettänyt sähköpostin",
-    "error-invitation-code-not-exist": "Kutsukoodi ei ole olemassa",
+    "error-invitation-code-not-exist": "Kutsukoodia ei ole olemassa",
     "error-notAuthorized": "Sinulla ei ole oikeutta tarkastella tätä sivua.",
     "outgoing-webhooks": "Lähtevät Webkoukut",
     "outgoingWebhooksPopup-title": "Lähtevät Webkoukut",
-    "boardCardTitlePopup-title": "Kortin otsikko suodatin",
+    "boardCardTitlePopup-title": "Kortin otsikkosuodatin",
     "new-outgoing-webhook": "Uusi lähtevä Webkoukku",
     "no-name": "(Tuntematon)",
-    "Node_version": "Node versio",
+    "Node_version": "Node-versio",
     "OS_Arch": "Käyttöjärjestelmän arkkitehtuuri",
-    "OS_Cpus": "Käyttöjärjestelmän CPU määrä",
+    "OS_Cpus": "Käyttöjärjestelmän CPU-määrä",
     "OS_Freemem": "Käyttöjärjestelmän vapaa muisti",
     "OS_Loadavg": "Käyttöjärjestelmän kuorman keskiarvo",
     "OS_Platform": "Käyttöjärjestelmäalusta",
@@ -548,13 +548,13 @@
     "delete-board-confirm-popup": "Kaikki listat, kortit, tunnisteet ja toimet poistetaan ja et pysty palauttamaan taulun sisältöä. Tätä ei voi peruuttaa.",
     "boardDeletePopup-title": "Poista taulu?",
     "delete-board": "Poista taulu",
-    "default-subtasks-board": "Alitehtävät __board__ taululle",
+    "default-subtasks-board": "Alitehtävät taululle __board__",
     "default": "Oletus",
     "queue": "Jono",
-    "subtask-settings": "Alitehtävä asetukset",
-    "boardSubtaskSettingsPopup-title": "Taulu alitehtävien asetukset",
+    "subtask-settings": "Alitehtävä-asetukset",
+    "boardSubtaskSettingsPopup-title": "Taulualitehtävien asetukset",
     "show-subtasks-field": "Korteilla voi olla alitehtäviä",
-    "deposit-subtasks-board": "Tallenta alitehtävät tälle taululle:",
+    "deposit-subtasks-board": "Talleta alitehtävät tälle taululle:",
     "deposit-subtasks-list": "Laskeutumislista alatehtäville tallennettu tänne:",
     "show-parent-in-minicard": "Näytä ylätehtävä minikortilla:",
     "prefix-with-full-path": "Etuliite koko polulla",
@@ -562,7 +562,7 @@
     "subtext-with-full-path": "Aliteksti koko polulla",
     "subtext-with-parent": "Aliteksti ylätehtävällä",
     "change-card-parent": "Muuta kortin ylätehtävää",
-    "parent-card": "Ylätehtävä kortti",
+    "parent-card": "Ylätehtäväkortti",
     "source-board": "Lähdetaulu",
     "no-parent": "Älä näytä ylätehtävää",
     "activity-added-label": "lisätty tunniste '%s' kohteeseen %s",
@@ -576,7 +576,7 @@
     "r-rule": "Sääntö",
     "r-add-trigger": "Lisää liipaisin",
     "r-add-action": "Lisää toimi",
-    "r-board-rules": "Taulu säännöt",
+    "r-board-rules": "Taulusäännöt",
     "r-add-rule": "Lisää sääntö",
     "r-view-rule": "Näytä sääntö",
     "r-delete-rule": "Poista sääntö",
@@ -682,10 +682,10 @@
     "error-undefined": "Jotain meni pieleen",
     "error-ldap-login": "Virhe tapahtui yrittäessä kirjautua sisään",
     "display-authentication-method": "Näytä kirjautumistapa",
-    "default-authentication-method": "Oletus kirjautumistapa",
+    "default-authentication-method": "Oletuskirjautumistapa",
     "duplicate-board": "Tee kaksoiskappale taulusta",
     "people-number": "Ihmisten määrä on:",
-    "swimlaneDeletePopup-title": "Poista Swimlane ?",
+    "swimlaneDeletePopup-title": "Poista Swimlane?",
     "swimlane-delete-pop": "Kaikki toimet poistetaan toimintasyötteestä ja swimlanen poistaminen on lopullista. Tätä ei pysty peruuttamaan.",
     "restore-all": "Palauta kaikki",
     "delete-all": "Poista kaikki",

+ 15 - 8
models/export.js

@@ -6,27 +6,34 @@ if (Meteor.isServer) {
   // `ApiRoutes.path('boards/export', boardId)``
   // on the client instead of copy/pasting the route path manually between the
   // client and the server.
-  /*
-   * This route is used to export the board FROM THE APPLICATION.
-   * If user is already logged-in, pass loginToken as param "authToken":
-   * '/api/boards/:boardId/export?authToken=:token'
+  /**
+   * @operation export
+   * @tag Boards
+   *
+   * @summary This route is used to export the board.
+   *
+   * @description If user is already logged-in, pass loginToken as param
+   * "authToken": '/api/boards/:boardId/export?authToken=:token'
    *
    * See https://blog.kayla.com.au/server-side-route-authentication-in-meteor/
    * for detailed explanations
+   *
+   * @param {string} boardId the ID of the board we are exporting
+   * @param {string} authToken the loginToken
    */
-
-
   JsonRoutes.add('get', '/api/boards/:boardId/export', function(req, res) {
     const boardId = req.params.boardId;
     let user = null;
-    // todo XXX for real API, first look for token in Authentication: header
-    // then fallback to parameter
+
     const loginToken = req.query.authToken;
     if (loginToken) {
       const hashToken = Accounts._hashLoginToken(loginToken);
       user = Meteor.users.findOne({
         'services.resume.loginTokens.hashedToken': hashToken,
       });
+    } else if (!Meteor.settings.public.sandstorm) {
+      Authentication.checkUserId(req.userId);
+      user = Users.findOne({ _id: req.userId, isAdmin: true });
     }
 
     const exporter = new Exporter(boardId);

+ 1 - 1
openapi/generate_openapi.py

@@ -678,7 +678,7 @@ def parse_schemas(schemas_dir):
                 data = ''.join(f.readlines())
                 try:
                     # if the file failed, it's likely it doesn't contain a schema
-                    program = esprima.parseScript(data, options={'comment': True, 'loc': True})
+                    program = esprima.parseModule(data, options={'comment': True, 'loc': True})
                 except:
                     continue
 

+ 1 - 1
package.json

@@ -1,6 +1,6 @@
 {
   "name": "wekan",
-  "version": "v2.72.0",
+  "version": "v2.73.0",
   "description": "Open-Source kanban",
   "private": true,
   "scripts": {

+ 2 - 2
sandstorm-pkgdef.capnp

@@ -22,10 +22,10 @@ const pkgdef :Spk.PackageDefinition = (
     appTitle = (defaultText = "Wekan"),
     # The name of the app as it is displayed to the user.
 
-    appVersion = 274,
+    appVersion = 275,
     # Increment this for every release.
 
-    appMarketingVersion = (defaultText = "2.72.0~2019-05-13"),
+    appMarketingVersion = (defaultText = "2.73.0~2019-05-14"),
     # Human-readable presentation of the app version.
 
     minUpgradableAppVersion = 0,

+ 8 - 4
server/publications/boards.js

@@ -59,9 +59,12 @@ Meteor.publish('archivedBoards', function() {
   });
 });
 
-Meteor.publishRelations('board', function(boardId) {
+// If isArchived = false, this will only return board elements which are not archived.
+// If isArchived = true, this will only return board elements which are archived.
+Meteor.publishRelations('board', function(boardId, isArchived) {
   this.unblock();
   check(boardId, String);
+  check(isArchived, Boolean);
   const thisUserId = this.userId;
 
   this.cursor(Boards.find({
@@ -75,8 +78,8 @@ Meteor.publishRelations('board', function(boardId) {
     ],
   // Sort required to ensure oplog usage
   }, { limit: 1, sort: { _id: 1 } }), function(boardId, board) {
-    this.cursor(Lists.find({ boardId }));
-    this.cursor(Swimlanes.find({ boardId }));
+    this.cursor(Lists.find({ boardId, archived: isArchived }));
+    this.cursor(Swimlanes.find({ boardId,  archived: isArchived  }));
     this.cursor(Integrations.find({ boardId }));
     this.cursor(CustomFields.find({ boardIds: {$in: [boardId]} }, { sort: { name: 1 } }));
 
@@ -115,8 +118,9 @@ Meteor.publishRelations('board', function(boardId) {
     parentCards.selector = (_ids) => ({ parentId: _ids });
     const boards = this.join(Boards);
     const subCards = this.join(Cards);
+    subCards.selector = (_ids) => ({ archived: isArchived });
 
-    this.cursor(Cards.find({ boardId: {$in: [boardId,  board.subtasksDefaultBoardId]}}), function(cardId, card) {
+    this.cursor(Cards.find({ boardId: {$in: [boardId,  board.subtasksDefaultBoardId]}, archived: isArchived }), function(cardId, card) {
       if (card.type === 'cardType-linkedCard') {
         const impCardId = card.linkedId;
         subCards.push(impCardId);

+ 1 - 1
server/publications/fast-render.js

@@ -5,5 +5,5 @@ FastRender.onAllRoutes(function() {
 });
 
 FastRender.route('/b/:id/:slug', function({ id }) {
-  this.subscribe('board', id);
+  this.subscribe('board', id, false);
 });