mirror of
https://github.com/hedgedoc/hedgedoc.git
synced 2025-05-17 16:44:49 -04:00
Merge branch 'develop' into develop
This commit is contained in:
commit
e15fb2c8a3
6 changed files with 158 additions and 38 deletions
2
.idea/copyright/hedgedoc.xml
generated
2
.idea/copyright/hedgedoc.xml
generated
|
@ -1,6 +1,6 @@
|
|||
<component name="CopyrightManager">
|
||||
<copyright>
|
||||
<option name="notice" value="SPDX-FileCopyrightText: 2020 The HedgeDoc developers (see AUTHORS file) SPDX-License-Identifier: AGPL-3.0-only" />
|
||||
<option name="notice" value="SPDX-FileCopyrightText: $today.year The HedgeDoc developers (see AUTHORS file) SPDX-License-Identifier: AGPL-3.0-only" />
|
||||
<option name="myName" value="hedgedoc" />
|
||||
</copyright>
|
||||
</component>
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
History of CodiMD
|
||||
===
|
||||
# History of HedgeDoc
|
||||
|
||||
## It started with HackMD
|
||||
|
||||
|
@ -27,14 +26,29 @@ project), as people mistook it for an open core development model.
|
|||
|
||||
## CodiMD went independent
|
||||
|
||||
In March 2019, a discussion over licensing, governance and the future of CodiMD
|
||||
lead to the formation of a distinct GitHub organization. Up to that point, the
|
||||
community project resided in the organization of hackmdio but was for the most
|
||||
part self-organized.
|
||||
In March 2019, a discussion over licensing, governance and the future of CodiMD lead to the formation of a distinct
|
||||
GitHub organization. Up to that point, the community project resided in the organization of hackmdio but was for the
|
||||
most part self-organized.
|
||||
|
||||
During that debate, we did not reach an agreement that would have allowed us to
|
||||
move the repository, so we simply forked it. We still welcome the HackMD team
|
||||
as part of our community, especially since a large portion of this code base
|
||||
During that debate, we did not reach an agreement that would have allowed us to move the repository, so we simply forked
|
||||
it. We still welcome the HackMD team as part of our community, especially since a large portion of this code base
|
||||
originated with them.
|
||||
|
||||
*For the debate that lead to this step, please refer to the [governance debate](https://github.com/hackmdio/hackmd/issues/1170) and [the announcement of the new repository](https://github.com/codimd/server/issues/10).*
|
||||
*For the debate that lead to this step, please refer to
|
||||
the [governance debate](https://github.com/hackmdio/hackmd/issues/1170)
|
||||
and [the announcement of the new repository](https://github.com/hedgedoc/hedgedoc/issues/10).*
|
||||
|
||||
## CodiMD became HedgeDoc
|
||||
|
||||
With two actively named forks sharing the same name,
|
||||
both [insisting on being the original/actual owner of the name CodiMD](https://github.com/hackmdio/codimd/issues/1219),
|
||||
people became rightfully confused about the projects sharing the same name.
|
||||
|
||||
After roughly a year of being stuck on the name issue, the HedgeDoc community decided to take action and started
|
||||
a [renaming process in April 2020](https://community.codimd.org/t/renaming-yet-another-time/102). With a good head start
|
||||
in the amount of names, it was decided that an entire rebranding should take place and therefore, after
|
||||
a [name was agreed on in July 2020](https://community.codimd.org/t/codimd-becomes-hedgedoc/170), the next step was
|
||||
to [find a logo](https://community.codimd.org/t/time-to-find-the-hedgedoc-logo/171).
|
||||
|
||||
In November of 2020, roughly 7 months after the initiative was started, a logo was found, the rebranding of the
|
||||
application as well as all community pages took place and the time of name conflicts was over. (hopefully.)
|
||||
|
|
|
@ -39,7 +39,7 @@
|
|||
"rimraf": "3.0.2",
|
||||
"rxjs": "6.6.3",
|
||||
"shortid": "2.2.16",
|
||||
"sqlite3": "5.0.0",
|
||||
"sqlite3": "5.0.1",
|
||||
"swagger-ui-express": "4.1.6",
|
||||
"typeorm": "0.2.29"
|
||||
},
|
||||
|
|
|
@ -10,12 +10,13 @@ import {
|
|||
Delete,
|
||||
Get,
|
||||
Header,
|
||||
NotFoundException,
|
||||
Param,
|
||||
Post,
|
||||
Put,
|
||||
} from '@nestjs/common';
|
||||
import { NotInDBError } from '../../../errors/errors';
|
||||
import { ConsoleLoggerService } from '../../../logger/console-logger.service';
|
||||
import { NoteMetadataUpdateDto } from '../../../notes/note-metadata.dto';
|
||||
import { NotePermissionsUpdateDto } from '../../../notes/note-permissions.dto';
|
||||
import { NotesService } from '../../../notes/notes.service';
|
||||
import { RevisionsService } from '../../../revisions/revisions.service';
|
||||
|
@ -38,8 +39,15 @@ export class NotesController {
|
|||
}
|
||||
|
||||
@Get(':noteIdOrAlias')
|
||||
getNote(@Param('noteIdOrAlias') noteIdOrAlias: string) {
|
||||
return this.noteService.getNoteDtoByIdOrAlias(noteIdOrAlias);
|
||||
async getNote(@Param('noteIdOrAlias') noteIdOrAlias: string) {
|
||||
try {
|
||||
return await this.noteService.getNoteDtoByIdOrAlias(noteIdOrAlias);
|
||||
} catch (e) {
|
||||
if (e instanceof NotInDBError) {
|
||||
throw new NotFoundException(e.message);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Post(':noteAlias')
|
||||
|
@ -54,7 +62,14 @@ export class NotesController {
|
|||
@Delete(':noteIdOrAlias')
|
||||
async deleteNote(@Param('noteIdOrAlias') noteIdOrAlias: string) {
|
||||
this.logger.debug('Deleting note: ' + noteIdOrAlias);
|
||||
await this.noteService.deleteNoteByIdOrAlias(noteIdOrAlias);
|
||||
try {
|
||||
await this.noteService.deleteNoteByIdOrAlias(noteIdOrAlias);
|
||||
} catch (e) {
|
||||
if (e instanceof NotInDBError) {
|
||||
throw new NotFoundException(e.message);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
this.logger.debug('Successfully deleted ' + noteIdOrAlias);
|
||||
return;
|
||||
}
|
||||
|
@ -65,38 +80,88 @@ export class NotesController {
|
|||
@MarkdownBody() text: string,
|
||||
) {
|
||||
this.logger.debug('Got raw markdown:\n' + text);
|
||||
return this.noteService.updateNoteByIdOrAlias(noteIdOrAlias, text);
|
||||
try {
|
||||
return await this.noteService.updateNoteByIdOrAlias(noteIdOrAlias, text);
|
||||
} catch (e) {
|
||||
if (e instanceof NotInDBError) {
|
||||
throw new NotFoundException(e.message);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Get(':noteIdOrAlias/content')
|
||||
@Header('content-type', 'text/markdown')
|
||||
getNoteContent(@Param('noteIdOrAlias') noteIdOrAlias: string) {
|
||||
return this.noteService.getNoteContent(noteIdOrAlias);
|
||||
async getNoteContent(@Param('noteIdOrAlias') noteIdOrAlias: string) {
|
||||
try {
|
||||
return await this.noteService.getNoteContent(noteIdOrAlias);
|
||||
} catch (e) {
|
||||
if (e instanceof NotInDBError) {
|
||||
throw new NotFoundException(e.message);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Get(':noteIdOrAlias/metadata')
|
||||
getNoteMetadata(@Param('noteIdOrAlias') noteIdOrAlias: string) {
|
||||
return this.noteService.getNoteMetadata(noteIdOrAlias);
|
||||
async getNoteMetadata(@Param('noteIdOrAlias') noteIdOrAlias: string) {
|
||||
try {
|
||||
return await this.noteService.getNoteMetadata(noteIdOrAlias);
|
||||
} catch (e) {
|
||||
if (e instanceof NotInDBError) {
|
||||
throw new NotFoundException(e.message);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Put(':noteIdOrAlias/permissions')
|
||||
updateNotePermissions(
|
||||
async updateNotePermissions(
|
||||
@Param('noteIdOrAlias') noteIdOrAlias: string,
|
||||
@Body() updateDto: NotePermissionsUpdateDto,
|
||||
) {
|
||||
return this.noteService.updateNotePermissions(noteIdOrAlias, updateDto);
|
||||
try {
|
||||
return await this.noteService.updateNotePermissions(
|
||||
noteIdOrAlias,
|
||||
updateDto,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof NotInDBError) {
|
||||
throw new NotFoundException(e.message);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Get(':noteIdOrAlias/revisions')
|
||||
getNoteRevisions(@Param('noteIdOrAlias') noteIdOrAlias: string) {
|
||||
return this.revisionsService.getNoteRevisionMetadatas(noteIdOrAlias);
|
||||
async getNoteRevisions(@Param('noteIdOrAlias') noteIdOrAlias: string) {
|
||||
try {
|
||||
return await this.revisionsService.getNoteRevisionMetadatas(
|
||||
noteIdOrAlias,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof NotInDBError) {
|
||||
throw new NotFoundException(e.message);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
@Get(':noteIdOrAlias/revisions/:revisionId')
|
||||
getNoteRevision(
|
||||
async getNoteRevision(
|
||||
@Param('noteIdOrAlias') noteIdOrAlias: string,
|
||||
@Param('revisionId') revisionId: number,
|
||||
) {
|
||||
return this.revisionsService.getNoteRevision(noteIdOrAlias, revisionId);
|
||||
try {
|
||||
return await this.revisionsService.getNoteRevision(
|
||||
noteIdOrAlias,
|
||||
revisionId,
|
||||
);
|
||||
} catch (e) {
|
||||
if (e instanceof NotInDBError) {
|
||||
throw new NotFoundException(e.message);
|
||||
}
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -59,12 +59,19 @@ describe('Notes', () => {
|
|||
});
|
||||
|
||||
it(`GET /notes/{note}`, async () => {
|
||||
// check if we can succefully get a note that exists
|
||||
await notesService.createNote('This is a test note.', 'test1');
|
||||
const response = await request(app.getHttpServer())
|
||||
.get('/notes/test1')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(200);
|
||||
expect(response.body.content).toEqual('This is a test note.');
|
||||
|
||||
// check if a missing note correctly returns 404
|
||||
await request(app.getHttpServer())
|
||||
.get('/notes/i_dont_exist')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it(`POST /notes/{note}`, async () => {
|
||||
|
@ -85,9 +92,13 @@ describe('Notes', () => {
|
|||
it(`DELETE /notes/{note}`, async () => {
|
||||
await notesService.createNote('This is a test note.', 'test3');
|
||||
await request(app.getHttpServer()).delete('/notes/test3').expect(200);
|
||||
return expect(notesService.getNoteByIdOrAlias('test3')).rejects.toEqual(
|
||||
await expect(notesService.getNoteByIdOrAlias('test3')).rejects.toEqual(
|
||||
new NotInDBError("Note with id/alias 'test3' not found."),
|
||||
);
|
||||
// check if a missing note correctly returns 404
|
||||
await request(app.getHttpServer())
|
||||
.delete('/notes/i_dont_exist')
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it(`PUT /notes/{note}`, async () => {
|
||||
|
@ -97,9 +108,16 @@ describe('Notes', () => {
|
|||
.set('Content-Type', 'text/markdown')
|
||||
.send('New note text')
|
||||
.expect(200);
|
||||
return expect(
|
||||
await expect(
|
||||
(await notesService.getNoteDtoByIdOrAlias('test4')).content,
|
||||
).toEqual('New note text');
|
||||
|
||||
// check if a missing note correctly returns 404
|
||||
await request(app.getHttpServer())
|
||||
.put('/notes/i_dont_exist')
|
||||
.set('Content-Type', 'text/markdown')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it(`GET /notes/{note}/metadata`, async () => {
|
||||
|
@ -124,6 +142,12 @@ describe('Notes', () => {
|
|||
expect(typeof metadata.body.updateUser.photo).toEqual('string');
|
||||
expect(typeof metadata.body.viewCount).toEqual('number');
|
||||
expect(metadata.body.editedBy).toEqual([]);
|
||||
|
||||
// check if a missing note correctly returns 404
|
||||
await request(app.getHttpServer())
|
||||
.get('/notes/i_dont_exist/metadata')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it(`GET /notes/{note}/revisions`, async () => {
|
||||
|
@ -133,6 +157,12 @@ describe('Notes', () => {
|
|||
.expect('Content-Type', /json/)
|
||||
.expect(200);
|
||||
expect(response.body).toHaveLength(1);
|
||||
|
||||
// check if a missing note correctly returns 404
|
||||
await request(app.getHttpServer())
|
||||
.get('/notes/i_dont_exist/revisions')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it(`GET /notes/{note}/revisions/{revision-id}`, async () => {
|
||||
|
@ -143,6 +173,12 @@ describe('Notes', () => {
|
|||
.expect('Content-Type', /json/)
|
||||
.expect(200);
|
||||
expect(response.body.content).toEqual('This is a test note.');
|
||||
|
||||
// check if a missing note correctly returns 404
|
||||
await request(app.getHttpServer())
|
||||
.get('/notes/i_dont_exist/revisions/1')
|
||||
.expect('Content-Type', /json/)
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
it(`GET /notes/{note}/content`, async () => {
|
||||
|
@ -151,6 +187,11 @@ describe('Notes', () => {
|
|||
.get('/notes/test9/content')
|
||||
.expect(200);
|
||||
expect(response.text).toEqual('This is a test note.');
|
||||
|
||||
// check if a missing note correctly returns 404
|
||||
await request(app.getHttpServer())
|
||||
.get('/notes/i_dont_exist/content')
|
||||
.expect(404);
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
|
|
18
yarn.lock
18
yarn.lock
|
@ -4942,10 +4942,10 @@ nice-try@^1.0.4:
|
|||
resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
|
||||
integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
|
||||
|
||||
node-addon-api@2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.0.tgz#f9afb8d777a91525244b01775ea0ddbe1125483b"
|
||||
integrity sha512-ASCL5U13as7HhOExbT6OlWJJUV/lLzL2voOSP1UVehpRD8FbSrSDjfScK/KwAvVTI5AS6r4VwbOMlIqtvRidnA==
|
||||
node-addon-api@^3.0.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-3.1.0.tgz#98b21931557466c6729e51cb77cd39c965f42239"
|
||||
integrity sha512-flmrDNB06LIl5lywUz7YlNGZH/5p0M7W28k8hzd9Lshtdh1wshD2Y+U4h9LD6KObOy1f+fEVdgprPrEymjM5uw==
|
||||
|
||||
node-emoji@1.10.0:
|
||||
version "1.10.0"
|
||||
|
@ -6287,12 +6287,12 @@ sprintf-js@~1.0.2:
|
|||
resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
|
||||
integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
|
||||
|
||||
sqlite3@5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.0.0.tgz#1bfef2151c6bc48a3ab1a6c126088bb8dd233566"
|
||||
integrity sha512-rjvqHFUaSGnzxDy2AHCwhHy6Zp6MNJzCPGYju4kD8yi6bze4d1/zMTg6C7JI49b7/EM7jKMTvyfN/4ylBKdwfw==
|
||||
sqlite3@5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/sqlite3/-/sqlite3-5.0.1.tgz#d5b58c8d1568bbaf13062eb9465982f36324f78a"
|
||||
integrity sha512-kh2lTIcYNfmVcvhVJihsYuPj9U0xzBbh6bmqILO2hkryWSC9RRhzYmkIDtJkJ+d8Kg4wZRJ0T1reyHUEspICfg==
|
||||
dependencies:
|
||||
node-addon-api "2.0.0"
|
||||
node-addon-api "^3.0.0"
|
||||
node-pre-gyp "^0.11.0"
|
||||
optionalDependencies:
|
||||
node-gyp "3.x"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue