2
0

migrations.js 21 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046
  1. import AccountSettings from '../models/accountSettings';
  2. import Actions from '../models/actions';
  3. import Activities from '../models/activities';
  4. import Announcements from '../models/announcements';
  5. import Boards from '../models/boards';
  6. import CardComments from '../models/cardComments';
  7. import Cards from '../models/cards';
  8. import ChecklistItems from '../models/checklistItems';
  9. import Checklists from '../models/checklists';
  10. import CustomFields from '../models/customFields';
  11. import Integrations from '../models/integrations';
  12. import InvitationCodes from '../models/invitationCodes';
  13. import Lists from '../models/lists';
  14. import Rules from '../models/rules';
  15. import Settings from '../models/settings';
  16. import Swimlanes from '../models/swimlanes';
  17. import Triggers from '../models/triggers';
  18. import UnsavedEdits from '../models/unsavedEdits';
  19. import Users from '../models/users';
  20. // Anytime you change the schema of one of the collection in a non-backward
  21. // compatible way you have to write a migration in this file using the following
  22. // API:
  23. //
  24. // Migrations.add(name, migrationCallback, optionalOrder);
  25. // Note that we have extra migrations defined in `sandstorm.js` that are
  26. // exclusive to Sandstorm and shouldn’t be executed in the general case.
  27. // XXX I guess if we had ES6 modules we could
  28. // `import { isSandstorm } from sandstorm.js` and define the migration here as
  29. // well, but for now I want to avoid definied too many globals.
  30. // In the context of migration functions we don't want to validate database
  31. // mutation queries against the current (ie, latest) collection schema. Doing
  32. // that would work at the time we write the migration but would break in the
  33. // future when we'll update again the concerned collection schema.
  34. //
  35. // To prevent this bug we always have to disable the schema validation and
  36. // argument transformations. We generally use the shorthandlers defined below.
  37. const noValidate = {
  38. validate: false,
  39. filter: false,
  40. autoConvert: false,
  41. removeEmptyStrings: false,
  42. getAutoValues: false,
  43. };
  44. const noValidateMulti = { ...noValidate, multi: true };
  45. Migrations.add('board-background-color', () => {
  46. const defaultColor = '#16A085';
  47. Boards.update(
  48. {
  49. background: {
  50. $exists: false,
  51. },
  52. },
  53. {
  54. $set: {
  55. background: {
  56. type: 'color',
  57. color: defaultColor,
  58. },
  59. },
  60. },
  61. noValidateMulti,
  62. );
  63. });
  64. Migrations.add('lowercase-board-permission', () => {
  65. ['Public', 'Private'].forEach(permission => {
  66. Boards.update(
  67. { permission },
  68. { $set: { permission: permission.toLowerCase() } },
  69. noValidateMulti,
  70. );
  71. });
  72. });
  73. // Security migration: see https://github.com/wekan/wekan/issues/99
  74. Migrations.add('change-attachments-type-for-non-images', () => {
  75. const newTypeForNonImage = 'application/octet-stream';
  76. Attachments.find().forEach(file => {
  77. if (!file.isImage()) {
  78. Attachments.update(
  79. file._id,
  80. {
  81. $set: {
  82. 'original.type': newTypeForNonImage,
  83. 'copies.attachments.type': newTypeForNonImage,
  84. },
  85. },
  86. noValidate,
  87. );
  88. }
  89. });
  90. });
  91. Migrations.add('card-covers', () => {
  92. Cards.find().forEach(card => {
  93. const cover = Attachments.findOne({ cardId: card._id, cover: true });
  94. if (cover) {
  95. Cards.update(card._id, { $set: { coverId: cover._id } }, noValidate);
  96. }
  97. });
  98. Attachments.update({}, { $unset: { cover: '' } }, noValidateMulti);
  99. });
  100. Migrations.add('use-css-class-for-boards-colors', () => {
  101. const associationTable = {
  102. '#27AE60': 'nephritis',
  103. '#C0392B': 'pomegranate',
  104. '#2980B9': 'belize',
  105. '#8E44AD': 'wisteria',
  106. '#2C3E50': 'midnight',
  107. '#E67E22': 'pumpkin',
  108. '#CD5A91': 'moderatepink',
  109. '#00AECC': 'strongcyan',
  110. '#4BBF6B': 'limegreen',
  111. '#2C3E51': 'dark',
  112. '#27AE61': 'relax',
  113. '#568BA2': 'corteza',
  114. '#499BEA': 'clearblue',
  115. '#596557': 'natural',
  116. '#2A80B8': 'modern',
  117. };
  118. Boards.find().forEach(board => {
  119. const oldBoardColor = board.background.color;
  120. const newBoardColor = associationTable[oldBoardColor];
  121. Boards.update(
  122. board._id,
  123. {
  124. $set: { color: newBoardColor },
  125. $unset: { background: '' },
  126. },
  127. noValidate,
  128. );
  129. });
  130. });
  131. Migrations.add('denormalize-star-number-per-board', () => {
  132. Boards.find().forEach(board => {
  133. const nStars = Users.find({ 'profile.starredBoards': board._id }).count();
  134. Boards.update(board._id, { $set: { stars: nStars } }, noValidate);
  135. });
  136. });
  137. // We want to keep a trace of former members so we can efficiently publish their
  138. // infos in the general board publication.
  139. Migrations.add('add-member-isactive-field', () => {
  140. Boards.find({}, { fields: { members: 1 } }).forEach(board => {
  141. const allUsersWithSomeActivity = _.chain(
  142. Activities.find(
  143. { boardId: board._id },
  144. { fields: { userId: 1 } },
  145. ).fetch(),
  146. )
  147. .pluck('userId')
  148. .uniq()
  149. .value();
  150. const currentUsers = _.pluck(board.members, 'userId');
  151. const formerUsers = _.difference(allUsersWithSomeActivity, currentUsers);
  152. const newMemberSet = [];
  153. board.members.forEach(member => {
  154. member.isActive = true;
  155. newMemberSet.push(member);
  156. });
  157. formerUsers.forEach(userId => {
  158. newMemberSet.push({
  159. userId,
  160. isAdmin: false,
  161. isActive: false,
  162. });
  163. });
  164. Boards.update(board._id, { $set: { members: newMemberSet } }, noValidate);
  165. });
  166. });
  167. Migrations.add('add-sort-checklists', () => {
  168. Checklists.find().forEach((checklist, index) => {
  169. if (!checklist.hasOwnProperty('sort')) {
  170. Checklists.direct.update(
  171. checklist._id,
  172. { $set: { sort: index } },
  173. noValidate,
  174. );
  175. }
  176. checklist.items.forEach((item, index) => {
  177. if (!item.hasOwnProperty('sort')) {
  178. Checklists.direct.update(
  179. { _id: checklist._id, 'items._id': item._id },
  180. { $set: { 'items.$.sort': index } },
  181. noValidate,
  182. );
  183. }
  184. });
  185. });
  186. });
  187. Migrations.add('add-swimlanes', () => {
  188. Boards.find().forEach(board => {
  189. const swimlaneId = board.getDefaultSwimline()._id;
  190. Cards.find({ boardId: board._id }).forEach(card => {
  191. if (!card.hasOwnProperty('swimlaneId')) {
  192. Cards.direct.update(
  193. { _id: card._id },
  194. { $set: { swimlaneId } },
  195. noValidate,
  196. );
  197. }
  198. });
  199. });
  200. });
  201. Migrations.add('add-views', () => {
  202. Boards.find().forEach(board => {
  203. if (!board.hasOwnProperty('view')) {
  204. Boards.direct.update(
  205. { _id: board._id },
  206. { $set: { view: 'board-view-swimlanes' } },
  207. noValidate,
  208. );
  209. }
  210. });
  211. });
  212. Migrations.add('add-checklist-items', () => {
  213. Checklists.find().forEach(checklist => {
  214. // Create new items
  215. _.sortBy(checklist.items, 'sort').forEach((item, index) => {
  216. ChecklistItems.direct.insert({
  217. title: item.title ? item.title : 'Checklist',
  218. sort: index,
  219. isFinished: item.isFinished,
  220. checklistId: checklist._id,
  221. cardId: checklist.cardId,
  222. });
  223. });
  224. // Delete old ones
  225. Checklists.direct.update(
  226. { _id: checklist._id },
  227. { $unset: { items: 1 } },
  228. noValidate,
  229. );
  230. });
  231. });
  232. Migrations.add('add-card-types', () => {
  233. Cards.find().forEach(card => {
  234. Cards.direct.update(
  235. { _id: card._id },
  236. {
  237. $set: {
  238. type: 'cardType-card',
  239. linkedId: null,
  240. },
  241. },
  242. noValidate,
  243. );
  244. });
  245. });
  246. Migrations.add('add-custom-fields-to-cards', () => {
  247. Cards.update(
  248. {
  249. customFields: {
  250. $exists: false,
  251. },
  252. },
  253. {
  254. $set: {
  255. customFields: [],
  256. },
  257. },
  258. noValidateMulti,
  259. );
  260. });
  261. Migrations.add('add-requester-field', () => {
  262. Cards.update(
  263. {
  264. requestedBy: {
  265. $exists: false,
  266. },
  267. },
  268. {
  269. $set: {
  270. requestedBy: '',
  271. },
  272. },
  273. noValidateMulti,
  274. );
  275. });
  276. Migrations.add('add-assigner-field', () => {
  277. Cards.update(
  278. {
  279. assignedBy: {
  280. $exists: false,
  281. },
  282. },
  283. {
  284. $set: {
  285. assignedBy: '',
  286. },
  287. },
  288. noValidateMulti,
  289. );
  290. });
  291. Migrations.add('add-parent-field-to-cards', () => {
  292. Cards.update(
  293. {
  294. parentId: {
  295. $exists: false,
  296. },
  297. },
  298. {
  299. $set: {
  300. parentId: '',
  301. },
  302. },
  303. noValidateMulti,
  304. );
  305. });
  306. Migrations.add('add-subtasks-boards', () => {
  307. Boards.update(
  308. {
  309. subtasksDefaultBoardId: {
  310. $exists: false,
  311. },
  312. },
  313. {
  314. $set: {
  315. subtasksDefaultBoardId: null,
  316. subtasksDefaultListId: null,
  317. },
  318. },
  319. noValidateMulti,
  320. );
  321. });
  322. Migrations.add('add-subtasks-sort', () => {
  323. Boards.update(
  324. {
  325. subtaskSort: {
  326. $exists: false,
  327. },
  328. },
  329. {
  330. $set: {
  331. subtaskSort: -1,
  332. },
  333. },
  334. noValidateMulti,
  335. );
  336. });
  337. Migrations.add('add-subtasks-allowed', () => {
  338. Boards.update(
  339. {
  340. allowsSubtasks: {
  341. $exists: false,
  342. },
  343. },
  344. {
  345. $set: {
  346. allowsSubtasks: true,
  347. },
  348. },
  349. noValidateMulti,
  350. );
  351. });
  352. Migrations.add('add-subtasks-allowed', () => {
  353. Boards.update(
  354. {
  355. presentParentTask: {
  356. $exists: false,
  357. },
  358. },
  359. {
  360. $set: {
  361. presentParentTask: 'no-parent',
  362. },
  363. },
  364. noValidateMulti,
  365. );
  366. });
  367. Migrations.add('add-authenticationMethod', () => {
  368. Users.update(
  369. {
  370. authenticationMethod: {
  371. $exists: false,
  372. },
  373. },
  374. {
  375. $set: {
  376. authenticationMethod: 'password',
  377. },
  378. },
  379. noValidateMulti,
  380. );
  381. });
  382. Migrations.add('remove-tag', () => {
  383. Users.update(
  384. {},
  385. {
  386. $unset: {
  387. 'profile.tags': 1,
  388. },
  389. },
  390. noValidateMulti,
  391. );
  392. });
  393. Migrations.add('remove-customFields-references-broken', () => {
  394. Cards.update(
  395. { 'customFields.$value': null },
  396. {
  397. $pull: {
  398. customFields: { value: null },
  399. },
  400. },
  401. noValidateMulti,
  402. );
  403. });
  404. Migrations.add('add-product-name', () => {
  405. Settings.update(
  406. {
  407. productName: {
  408. $exists: false,
  409. },
  410. },
  411. {
  412. $set: {
  413. productName: '',
  414. },
  415. },
  416. noValidateMulti,
  417. );
  418. });
  419. Migrations.add('add-hide-logo', () => {
  420. Settings.update(
  421. {
  422. hideLogo: {
  423. $exists: false,
  424. },
  425. },
  426. {
  427. $set: {
  428. hideLogo: false,
  429. },
  430. },
  431. noValidateMulti,
  432. );
  433. });
  434. Migrations.add('add-displayAuthenticationMethod', () => {
  435. Settings.update(
  436. {
  437. displayAuthenticationMethod: {
  438. $exists: false,
  439. },
  440. },
  441. {
  442. $set: {
  443. displayAuthenticationMethod: true,
  444. },
  445. },
  446. noValidateMulti,
  447. );
  448. });
  449. Migrations.add('add-defaultAuthenticationMethod', () => {
  450. Settings.update(
  451. {
  452. defaultAuthenticationMethod: {
  453. $exists: false,
  454. },
  455. },
  456. {
  457. $set: {
  458. defaultAuthenticationMethod: 'password',
  459. },
  460. },
  461. noValidateMulti,
  462. );
  463. });
  464. Migrations.add('add-templates', () => {
  465. Boards.update(
  466. {
  467. type: {
  468. $exists: false,
  469. },
  470. },
  471. {
  472. $set: {
  473. type: 'board',
  474. },
  475. },
  476. noValidateMulti,
  477. );
  478. Swimlanes.update(
  479. {
  480. type: {
  481. $exists: false,
  482. },
  483. },
  484. {
  485. $set: {
  486. type: 'swimlane',
  487. },
  488. },
  489. noValidateMulti,
  490. );
  491. Lists.update(
  492. {
  493. type: {
  494. $exists: false,
  495. },
  496. swimlaneId: {
  497. $exists: false,
  498. },
  499. },
  500. {
  501. $set: {
  502. type: 'list',
  503. swimlaneId: '',
  504. },
  505. },
  506. noValidateMulti,
  507. );
  508. Users.find({
  509. 'profile.templatesBoardId': {
  510. $exists: false,
  511. },
  512. }).forEach(user => {
  513. // Create board and swimlanes
  514. Boards.insert(
  515. {
  516. title: TAPi18n.__('templates'),
  517. permission: 'private',
  518. type: 'template-container',
  519. members: [
  520. {
  521. userId: user._id,
  522. isAdmin: true,
  523. isActive: true,
  524. isNoComments: false,
  525. isCommentOnly: false,
  526. },
  527. ],
  528. },
  529. (err, boardId) => {
  530. // Insert the reference to our templates board
  531. Users.update(user._id, {
  532. $set: { 'profile.templatesBoardId': boardId },
  533. });
  534. // Insert the card templates swimlane
  535. Swimlanes.insert(
  536. {
  537. title: TAPi18n.__('card-templates-swimlane'),
  538. boardId,
  539. sort: 1,
  540. type: 'template-container',
  541. },
  542. (err, swimlaneId) => {
  543. // Insert the reference to out card templates swimlane
  544. Users.update(user._id, {
  545. $set: { 'profile.cardTemplatesSwimlaneId': swimlaneId },
  546. });
  547. },
  548. );
  549. // Insert the list templates swimlane
  550. Swimlanes.insert(
  551. {
  552. title: TAPi18n.__('list-templates-swimlane'),
  553. boardId,
  554. sort: 2,
  555. type: 'template-container',
  556. },
  557. (err, swimlaneId) => {
  558. // Insert the reference to out list templates swimlane
  559. Users.update(user._id, {
  560. $set: { 'profile.listTemplatesSwimlaneId': swimlaneId },
  561. });
  562. },
  563. );
  564. // Insert the board templates swimlane
  565. Swimlanes.insert(
  566. {
  567. title: TAPi18n.__('board-templates-swimlane'),
  568. boardId,
  569. sort: 3,
  570. type: 'template-container',
  571. },
  572. (err, swimlaneId) => {
  573. // Insert the reference to out board templates swimlane
  574. Users.update(user._id, {
  575. $set: { 'profile.boardTemplatesSwimlaneId': swimlaneId },
  576. });
  577. },
  578. );
  579. },
  580. );
  581. });
  582. });
  583. Migrations.add('fix-circular-reference_', () => {
  584. Cards.find().forEach(card => {
  585. if (card.parentId === card._id) {
  586. Cards.update(card._id, { $set: { parentId: '' } }, noValidateMulti);
  587. }
  588. });
  589. });
  590. Migrations.add('mutate-boardIds-in-customfields', () => {
  591. CustomFields.find().forEach(cf => {
  592. CustomFields.update(
  593. cf,
  594. {
  595. $set: {
  596. boardIds: [cf.boardId],
  597. },
  598. $unset: {
  599. boardId: '',
  600. },
  601. },
  602. noValidateMulti,
  603. );
  604. });
  605. });
  606. const modifiedAtTables = [
  607. AccountSettings,
  608. Actions,
  609. Activities,
  610. Announcements,
  611. Boards,
  612. CardComments,
  613. Cards,
  614. ChecklistItems,
  615. Checklists,
  616. CustomFields,
  617. Integrations,
  618. InvitationCodes,
  619. Lists,
  620. Rules,
  621. Settings,
  622. Swimlanes,
  623. Triggers,
  624. UnsavedEdits,
  625. Users,
  626. ];
  627. Migrations.add('add-missing-created-and-modified', () => {
  628. Promise.all(
  629. modifiedAtTables.map(db =>
  630. db
  631. .rawCollection()
  632. .update(
  633. { modifiedAt: { $exists: false } },
  634. { $set: { modifiedAt: new Date() } },
  635. { multi: true },
  636. )
  637. .then(() =>
  638. db
  639. .rawCollection()
  640. .update(
  641. { createdAt: { $exists: false } },
  642. { $set: { createdAt: new Date() } },
  643. { multi: true },
  644. ),
  645. ),
  646. ),
  647. )
  648. .then(() => {
  649. // eslint-disable-next-line no-console
  650. console.info('Successfully added createdAt and updatedAt to all tables');
  651. })
  652. .catch(e => {
  653. // eslint-disable-next-line no-console
  654. console.error(e);
  655. });
  656. });
  657. Migrations.add('fix-incorrect-dates', () => {
  658. const tables = [
  659. AccountSettings,
  660. Actions,
  661. Activities,
  662. Announcements,
  663. Boards,
  664. CardComments,
  665. Cards,
  666. ChecklistItems,
  667. Checklists,
  668. CustomFields,
  669. Integrations,
  670. InvitationCodes,
  671. Lists,
  672. Rules,
  673. Settings,
  674. Swimlanes,
  675. Triggers,
  676. UnsavedEdits,
  677. ];
  678. // Dates were previously created with Date.now() which is a number, not a date
  679. tables.forEach(t =>
  680. t
  681. .rawCollection()
  682. .find({ $or: [{ createdAt: { $type: 1 } }, { updatedAt: { $type: 1 } }] })
  683. .forEach(({ _id, createdAt, updatedAt }) => {
  684. t.rawCollection().update(
  685. { _id },
  686. {
  687. $set: {
  688. createdAt: new Date(createdAt),
  689. updatedAt: new Date(updatedAt),
  690. },
  691. },
  692. );
  693. }),
  694. );
  695. });
  696. Migrations.add('add-assignee', () => {
  697. Cards.update(
  698. {
  699. assignees: {
  700. $exists: false,
  701. },
  702. },
  703. {
  704. $set: {
  705. assignees: [],
  706. },
  707. },
  708. noValidateMulti,
  709. );
  710. });
  711. Migrations.add('add-profile-showDesktopDragHandles', () => {
  712. Users.update(
  713. {
  714. 'profile.showDesktopDragHandles': {
  715. $exists: false,
  716. },
  717. },
  718. {
  719. $set: {
  720. 'profile.showDesktopDragHandles': false,
  721. },
  722. },
  723. noValidateMulti,
  724. );
  725. });
  726. Migrations.add('add-profile-hiddenMinicardLabelText', () => {
  727. Users.update(
  728. {
  729. 'profile.hiddenMinicardLabelText': {
  730. $exists: false,
  731. },
  732. },
  733. {
  734. $set: {
  735. 'profile.hiddenMinicardLabelText': false,
  736. },
  737. },
  738. noValidateMulti,
  739. );
  740. });
  741. Migrations.add('add-receiveddate-allowed', () => {
  742. Boards.update(
  743. {
  744. allowsReceivedDate: {
  745. $exists: false,
  746. },
  747. },
  748. {
  749. $set: {
  750. allowsReceivedDate: true,
  751. },
  752. },
  753. noValidateMulti,
  754. );
  755. });
  756. Migrations.add('add-startdate-allowed', () => {
  757. Boards.update(
  758. {
  759. allowsStartDate: {
  760. $exists: false,
  761. },
  762. },
  763. {
  764. $set: {
  765. allowsStartDate: true,
  766. },
  767. },
  768. noValidateMulti,
  769. );
  770. });
  771. Migrations.add('add-duedate-allowed', () => {
  772. Boards.update(
  773. {
  774. allowsDueDate: {
  775. $exists: false,
  776. },
  777. },
  778. {
  779. $set: {
  780. allowsDueDate: true,
  781. },
  782. },
  783. noValidateMulti,
  784. );
  785. });
  786. Migrations.add('add-enddate-allowed', () => {
  787. Boards.update(
  788. {
  789. allowsEndDate: {
  790. $exists: false,
  791. },
  792. },
  793. {
  794. $set: {
  795. allowsEndDate: true,
  796. },
  797. },
  798. noValidateMulti,
  799. );
  800. });
  801. Migrations.add('add-members-allowed', () => {
  802. Boards.update(
  803. {
  804. allowsMembers: {
  805. $exists: false,
  806. },
  807. },
  808. {
  809. $set: {
  810. allowsMembers: true,
  811. },
  812. },
  813. noValidateMulti,
  814. );
  815. });
  816. Migrations.add('add-assignee-allowed', () => {
  817. Boards.update(
  818. {
  819. allowsAssignee: {
  820. $exists: false,
  821. },
  822. },
  823. {
  824. $set: {
  825. allowsAssignee: true,
  826. },
  827. },
  828. noValidateMulti,
  829. );
  830. });
  831. Migrations.add('add-labels-allowed', () => {
  832. Boards.update(
  833. {
  834. allowsLabels: {
  835. $exists: false,
  836. },
  837. },
  838. {
  839. $set: {
  840. allowsLabels: true,
  841. },
  842. },
  843. noValidateMulti,
  844. );
  845. });
  846. Migrations.add('add-checklists-allowed', () => {
  847. Boards.update(
  848. {
  849. allowsChecklists: {
  850. $exists: false,
  851. },
  852. },
  853. {
  854. $set: {
  855. allowsChecklists: true,
  856. },
  857. },
  858. noValidateMulti,
  859. );
  860. });
  861. Migrations.add('add-attachments-allowed', () => {
  862. Boards.update(
  863. {
  864. allowsAttachments: {
  865. $exists: false,
  866. },
  867. },
  868. {
  869. $set: {
  870. allowsAttachments: true,
  871. },
  872. },
  873. noValidateMulti,
  874. );
  875. });
  876. Migrations.add('add-comments-allowed', () => {
  877. Boards.update(
  878. {
  879. allowsComments: {
  880. $exists: false,
  881. },
  882. },
  883. {
  884. $set: {
  885. allowsComments: true,
  886. },
  887. },
  888. noValidateMulti,
  889. );
  890. });
  891. Migrations.add('add-assigned-by-allowed', () => {
  892. Boards.update(
  893. {
  894. allowsAssignedBy: {
  895. $exists: false,
  896. },
  897. },
  898. {
  899. $set: {
  900. allowsAssignedBy: true,
  901. },
  902. },
  903. noValidateMulti,
  904. );
  905. });
  906. Migrations.add('add-requested-by-allowed', () => {
  907. Boards.update(
  908. {
  909. allowsRequestedBy: {
  910. $exists: false,
  911. },
  912. },
  913. {
  914. $set: {
  915. allowsRequestedBy: true,
  916. },
  917. },
  918. noValidateMulti,
  919. );
  920. });
  921. Migrations.add('add-activities-allowed', () => {
  922. Boards.update(
  923. {
  924. allowsActivities: {
  925. $exists: false,
  926. },
  927. },
  928. {
  929. $set: {
  930. allowsActivities: true,
  931. },
  932. },
  933. noValidateMulti,
  934. );
  935. });
  936. Migrations.add('add-description-title-allowed', () => {
  937. Boards.update(
  938. {
  939. allowsDescriptionTitle: {
  940. $exists: false,
  941. },
  942. },
  943. {
  944. $set: {
  945. allowsDescriptionTitle: true,
  946. },
  947. },
  948. noValidateMulti,
  949. );
  950. });
  951. Migrations.add('add-description-text-allowed', () => {
  952. Boards.update(
  953. {
  954. allowsDescriptionText: {
  955. $exists: false,
  956. },
  957. },
  958. {
  959. $set: {
  960. allowsDescriptionText: true,
  961. },
  962. },
  963. noValidateMulti,
  964. );
  965. });
  966. Migrations.add('add-sort-field-to-boards', () => {
  967. Boards.find().forEach((board, index) => {
  968. if (!board.hasOwnProperty('sort')) {
  969. Boards.direct.update(board._id, { $set: { sort: index } }, noValidate);
  970. }
  971. });
  972. });
  973. Migrations.add('add-default-profile-view', () => {
  974. Users.find().forEach(user => {
  975. if (!user.hasOwnProperty('profile.boardView')) {
  976. // Set default view
  977. Users.direct.update(
  978. { _id: user._id },
  979. { $set: { 'profile.boardView': 'board-view-swimlanes' } },
  980. noValidate,
  981. );
  982. }
  983. });
  984. });