kopia lustrzana https://github.com/nextcloud/social
				
				
				
			
						commit
						5ec03e2db5
					
				| 
						 | 
				
			
			@ -11,50 +11,78 @@ env:
 | 
			
		|||
  APP_NAME: social
 | 
			
		||||
  BRANCH: ${{ github.base_ref }}
 | 
			
		||||
  CYPRESS_baseUrl: http://127.0.0.1:8082/index.php
 | 
			
		||||
  TESTING: true
 | 
			
		||||
 | 
			
		||||
jobs:
 | 
			
		||||
  cypress:
 | 
			
		||||
  init:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        # run 2 copies of the current job in parallel
 | 
			
		||||
        containers: [1, 2]
 | 
			
		||||
        node-version: ['12']
 | 
			
		||||
        php-versions: ['7.4']
 | 
			
		||||
 | 
			
		||||
    name: Runner ${{ matrix.containers }}
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Checkout app
 | 
			
		||||
        uses: actions/checkout@v2
 | 
			
		||||
 | 
			
		||||
      - name: Setup server
 | 
			
		||||
        run: |
 | 
			
		||||
          cd cypress
 | 
			
		||||
          docker-compose up -d
 | 
			
		||||
      - name: Set up node ${{ matrix.node-version }}
 | 
			
		||||
        uses: actions/setup-node@v1
 | 
			
		||||
      - name: Read package.json node and npm engines version
 | 
			
		||||
        uses: skjnldsv/read-package-engines-version-actions@v1.1
 | 
			
		||||
        id: versions
 | 
			
		||||
        with:
 | 
			
		||||
          node-version: ${{ matrix.node-version }}
 | 
			
		||||
          fallbackNode: "^12"
 | 
			
		||||
          fallbackNpm: "^6"
 | 
			
		||||
 | 
			
		||||
      - name: Set up node ${{ steps.versions.outputs.nodeVersion }}
 | 
			
		||||
        uses: actions/setup-node@v3
 | 
			
		||||
        with:
 | 
			
		||||
          cache: "npm"
 | 
			
		||||
          node-version: ${{ steps.versions.outputs.nodeVersion }}
 | 
			
		||||
 | 
			
		||||
      - name: Set up npm ${{ steps.versions.outputs.npmVersion }}
 | 
			
		||||
        run: npm i -g npm@"${{ steps.versions.outputs.npmVersion }}"
 | 
			
		||||
 | 
			
		||||
      - name: Install dependencies & build app
 | 
			
		||||
        run: |
 | 
			
		||||
          npm ci
 | 
			
		||||
          composer install
 | 
			
		||||
          TESTING=true npm run build --if-present
 | 
			
		||||
      - name: Wait for server
 | 
			
		||||
 | 
			
		||||
      - name: Save context
 | 
			
		||||
        uses: actions/cache@v3
 | 
			
		||||
        with:
 | 
			
		||||
          key: cypress-context-${{ github.run_id }}
 | 
			
		||||
          path: /home/runner/work/social
 | 
			
		||||
 | 
			
		||||
  cypress:
 | 
			
		||||
    runs-on: ubuntu-latest
 | 
			
		||||
    needs: init
 | 
			
		||||
 | 
			
		||||
    strategy:
 | 
			
		||||
      fail-fast: false
 | 
			
		||||
      matrix:
 | 
			
		||||
        # run multiple copies of the current job in parallel
 | 
			
		||||
        containers: [1, 2, 3, 4, 5, 6, 7, 8]
 | 
			
		||||
 | 
			
		||||
    name: runner ${{ matrix.containers }}
 | 
			
		||||
 | 
			
		||||
    steps:
 | 
			
		||||
      - name: Restore context
 | 
			
		||||
        uses: actions/cache@v3
 | 
			
		||||
        with:
 | 
			
		||||
          key: cypress-context-${{ github.run_id }}
 | 
			
		||||
          path: /home/runner/work/social
 | 
			
		||||
 | 
			
		||||
      - name: Setup server
 | 
			
		||||
        run: |
 | 
			
		||||
          npm install -g wait-on
 | 
			
		||||
          wait-on -i 500 -t 240000 $CYPRESS_baseUrl
 | 
			
		||||
          cd cypress
 | 
			
		||||
          docker-compose up -d
 | 
			
		||||
 | 
			
		||||
      - name: Wait for server
 | 
			
		||||
        run: npm run wait-on $CYPRESS_baseUrl
 | 
			
		||||
 | 
			
		||||
      - name: Enable app & configure server
 | 
			
		||||
        run: |
 | 
			
		||||
          cd cypress
 | 
			
		||||
          docker-compose exec --env APP_NAME=${{ env.APP_NAME }} -T nextcloud bash /initserver.sh
 | 
			
		||||
          docker-compose exec --env APP_NAME=${{ env.APP_NAME }} --env BRANCH=${{ env.BRANCH }} -T nextcloud bash /initserver.sh
 | 
			
		||||
 | 
			
		||||
      - name: Cypress run
 | 
			
		||||
        uses: cypress-io/github-action@v1
 | 
			
		||||
        uses: cypress-io/github-action@v4
 | 
			
		||||
        with:
 | 
			
		||||
          record: true
 | 
			
		||||
          parallel: true
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
const { defineConfig } = require('cypress')
 | 
			
		||||
const browserify = require('@cypress/browserify-preprocessor')
 | 
			
		||||
 | 
			
		||||
module.exports = defineConfig({
 | 
			
		||||
	projectId: '7mqhfh',
 | 
			
		||||
 | 
			
		||||
	viewportWidth: 1280,
 | 
			
		||||
	viewportHeight: 720,
 | 
			
		||||
	defaultCommandTimeout: 6000,
 | 
			
		||||
	retries: 1,
 | 
			
		||||
 | 
			
		||||
	env: {
 | 
			
		||||
		failSilently: false,
 | 
			
		||||
		type: 'actual',
 | 
			
		||||
	},
 | 
			
		||||
 | 
			
		||||
	screenshotsFolder: 'cypress/snapshots/actual',
 | 
			
		||||
	trashAssetsBeforeRuns: true,
 | 
			
		||||
 | 
			
		||||
	e2e: {
 | 
			
		||||
		baseUrl: 'http://localhost:8082/index.php',
 | 
			
		||||
 | 
			
		||||
		setupNodeEvents(on, config) {
 | 
			
		||||
			// Fix browserslist extend https://github.com/cypress-io/cypress/issues/2983#issuecomment-570616682
 | 
			
		||||
			on('file:preprocessor', browserify())
 | 
			
		||||
		},
 | 
			
		||||
	},
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			@ -1,7 +0,0 @@
 | 
			
		|||
{
 | 
			
		||||
  "baseUrl": "http://localhost:8082/index.php/",
 | 
			
		||||
  "projectId": "7mqhfh",
 | 
			
		||||
  "viewportWidth": 1280,
 | 
			
		||||
  "viewportHeight": 720,
 | 
			
		||||
  "defaultCommandTimeout": 6000
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,16 +1,18 @@
 | 
			
		|||
version: '3'
 | 
			
		||||
version: '3.7'
 | 
			
		||||
 | 
			
		||||
services:
 | 
			
		||||
    nextcloud:
 | 
			
		||||
        image: nextcloudci/server
 | 
			
		||||
        image: ghcr.io/nextcloud/continuous-integration-shallow-server
 | 
			
		||||
 | 
			
		||||
        ports:
 | 
			
		||||
            - 8082:80
 | 
			
		||||
 | 
			
		||||
        environment:
 | 
			
		||||
            CYPRESS_baseUrl: "http://127.0.0.1:8082/index.php"
 | 
			
		||||
            BRANCH: master
 | 
			
		||||
            BRANCH: "${BRANCH:-master}"
 | 
			
		||||
 | 
			
		||||
        volumes:
 | 
			
		||||
            - ../:/var/www/html/apps/social
 | 
			
		||||
            # Using fallback to make sure this script doesn't mess
 | 
			
		||||
            # with the mounting if APP_NAME is not provided.
 | 
			
		||||
            - ../:/var/www/html/apps/${APP_NAME:-social}
 | 
			
		||||
            - ./initserver.sh:/initserver.sh
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,4 +1,4 @@
 | 
			
		|||
let userId = 'janedoe' + Date.now();
 | 
			
		||||
const userId = 'janedoe' + Date.now()
 | 
			
		||||
 | 
			
		||||
describe('Social app setup', function() {
 | 
			
		||||
	before(function() {
 | 
			
		||||
| 
						 | 
				
			
			@ -6,10 +6,6 @@ describe('Social app setup', function() {
 | 
			
		|||
		cy.login(userId, 'p4ssw0rd')
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	beforeEach(() => {
 | 
			
		||||
		Cypress.Cookies.preserveOnce('nc_username', 'nc_token', 'nc_session_id', 'oc_sessionPassphrase');
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	it('See the welcome message', function() {
 | 
			
		||||
		cy.visit('/apps/social/')
 | 
			
		||||
		cy.get('.social__welcome').should('contain', 'Nextcloud becomes part of the federated social networks!')
 | 
			
		||||
| 
						 | 
				
			
			@ -26,7 +22,7 @@ describe('Social app setup', function() {
 | 
			
		|||
		cy.get('.app-navigation').contains('Direct messages').click()
 | 
			
		||||
		cy.get('.emptycontent').should('be.visible').contains('No direct messages found')
 | 
			
		||||
		cy.get('.app-navigation').contains('Profile').click()
 | 
			
		||||
		cy.get('.emptycontent').should('be.visible').contains('You haven\'t tooted yet')
 | 
			
		||||
		cy.get('.emptycontent').should('be.visible').contains('You have not tooted yet')
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			@ -20,15 +20,17 @@
 | 
			
		|||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
let userId = 'janedoe' + Date.now();
 | 
			
		||||
const userId = 'janedoe' + Date.now()
 | 
			
		||||
 | 
			
		||||
describe('Create posts', function() {
 | 
			
		||||
 | 
			
		||||
	before(function() {
 | 
			
		||||
		// ensure that the admin account is initialized for social
 | 
			
		||||
		cy.login('admin', 'admin', '/apps/social/')
 | 
			
		||||
		
 | 
			
		||||
 | 
			
		||||
		cy.nextcloudCreateUser(userId, 'p4ssw0rd')
 | 
			
		||||
		cy.logout()
 | 
			
		||||
 | 
			
		||||
		cy.login(userId, 'p4ssw0rd', '/apps/social/')
 | 
			
		||||
		cy.get('.app-content').should('be.visible')
 | 
			
		||||
	})
 | 
			
		||||
| 
						 | 
				
			
			@ -37,10 +39,6 @@ describe('Create posts', function() {
 | 
			
		|||
		cy.screenshot()
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	beforeEach(() => {
 | 
			
		||||
		Cypress.Cookies.preserveOnce('nc_username', 'nc_token', 'nc_session_id', 'oc_sessionPassphrase');
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	it('See the empty content illustration', function() {
 | 
			
		||||
		cy.get('.emptycontent').should('be.visible').contains('No posts found')
 | 
			
		||||
	})
 | 
			
		||||
| 
						 | 
				
			
			@ -49,19 +47,19 @@ describe('Create posts', function() {
 | 
			
		|||
		cy.visit('/apps/social/')
 | 
			
		||||
		cy.server()
 | 
			
		||||
		cy.route('POST', '/index.php/apps/social/api/v1/post').as('postMessage')
 | 
			
		||||
		cy.get('.new-post input[type=submit]')
 | 
			
		||||
		cy.get('.new-post button[type=submit]')
 | 
			
		||||
			.should('be.disabled')
 | 
			
		||||
		cy.get('.new-post').find('[contenteditable]').type('Hello world')
 | 
			
		||||
		cy.get('.new-post input[type=submit]')
 | 
			
		||||
		cy.get('.new-post button[type=submit]')
 | 
			
		||||
			.should('not.be.disabled')
 | 
			
		||||
		cy.get('.new-post input[type=submit]')
 | 
			
		||||
		cy.get('.new-post button[type=submit]')
 | 
			
		||||
			.click()
 | 
			
		||||
		cy.wait('@postMessage')
 | 
			
		||||
		cy.get('.social__timeline div.timeline-entry:first-child').should('contain', 'Hello world')
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	it('No longer see the empty content illustration', function() {
 | 
			
		||||
		cy.get('.emptycontent').should('not.be.visible')
 | 
			
		||||
		cy.get('.emptycontent').should('not.exist')
 | 
			
		||||
	})
 | 
			
		||||
 | 
			
		||||
	it('Write a post to followers with shift enter', function() {
 | 
			
		||||
| 
						 | 
				
			
			@ -78,11 +76,11 @@ describe('Create posts', function() {
 | 
			
		|||
		cy.server()
 | 
			
		||||
		cy.route('POST', '/index.php/apps/social/api/v1/post').as('postMessage')
 | 
			
		||||
		cy.route('GET', '/index.php/apps/social/api/v1/global/accounts/search')
 | 
			
		||||
		cy.get('.new-post').find('[contenteditable]').type('@adm', {delay: 500})
 | 
			
		||||
		cy.get('.new-post').find('[contenteditable]').type('@adm', { delay: 500 })
 | 
			
		||||
		cy.get('.tribute-container').should('be.visible')
 | 
			
		||||
		cy.get('.tribute-container ul li:first').contains('admin')
 | 
			
		||||
		cy.get('.new-post').find('[contenteditable]').type('{enter} Hello there', {delay: 100, force: true})
 | 
			
		||||
		cy.get('.new-post input[type=submit]')
 | 
			
		||||
		cy.get('.new-post').find('[contenteditable]').type('{enter} Hello there', { delay: 100, force: true })
 | 
			
		||||
		cy.get('.new-post button[type=submit]')
 | 
			
		||||
			.click()
 | 
			
		||||
		cy.wait('@postMessage')
 | 
			
		||||
		cy.get('.social__timeline div.timeline-entry:first-child').should('contain', '@admin')
 | 
			
		||||
| 
						 | 
				
			
			@ -93,9 +91,9 @@ describe('Create posts', function() {
 | 
			
		|||
		cy.server()
 | 
			
		||||
		cy.route('POST', '/index.php/apps/social/api/v1/post').as('postMessage')
 | 
			
		||||
		cy.route('GET', '/index.php/apps/social/api/v1/global/accounts/search')
 | 
			
		||||
		cy.get('.new-post').find('[contenteditable]').click({force: true}).type('@adm{enter} Hello world', {delay: 500, force: true})
 | 
			
		||||
		cy.get('.new-post').find('[contenteditable]').click({ force: true }).type('@adm{enter} Hello world', { delay: 500, force: true })
 | 
			
		||||
		cy.wait(500)
 | 
			
		||||
		cy.get('.new-post input[type=submit]').should('not.be.disabled')
 | 
			
		||||
		cy.get('.new-post button[type=submit]').should('not.be.disabled')
 | 
			
		||||
		const visibilityButton = cy.get('.new-post .options > div > button')
 | 
			
		||||
		visibilityButton.should('have.class', 'icon-contacts-dark')
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -105,7 +103,7 @@ describe('Create posts', function() {
 | 
			
		|||
		visibilityButton.click()
 | 
			
		||||
		cy.get('.new-post-form .popovermenu').should('not.be.visible')
 | 
			
		||||
 | 
			
		||||
		cy.get('.new-post input[type=submit]')
 | 
			
		||||
		cy.get('.new-post button[type=submit]')
 | 
			
		||||
			.click()
 | 
			
		||||
		cy.wait('@postMessage')
 | 
			
		||||
		cy.get('.social__timeline div.timeline-entry:first-child').should('contain', 'Hello world').should('contain', '@admin')
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,8 @@
 | 
			
		|||
#!/usr/bin/env bash
 | 
			
		||||
 | 
			
		||||
echo "APP_NAME: $APP_NAME"
 | 
			
		||||
echo "BRANCH: $BRANCH"
 | 
			
		||||
 | 
			
		||||
chown -R www-data:www-data /var/www/html/data
 | 
			
		||||
 | 
			
		||||
su www-data -c "
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,20 +0,0 @@
 | 
			
		|||
// ***********************************************************
 | 
			
		||||
// This example plugins/index.js can be used to load plugins
 | 
			
		||||
//
 | 
			
		||||
// You can change the location of this file or turn off loading
 | 
			
		||||
// the plugins file with the 'pluginsFile' configuration option.
 | 
			
		||||
//
 | 
			
		||||
// You can read more here:
 | 
			
		||||
// https://on.cypress.io/plugins-guide
 | 
			
		||||
// ***********************************************************
 | 
			
		||||
 | 
			
		||||
// This function is called when a project is opened or re-opened (e.g. due to
 | 
			
		||||
// the project's config changing)
 | 
			
		||||
 | 
			
		||||
const {
 | 
			
		||||
	addMatchImageSnapshotPlugin
 | 
			
		||||
} = require('cypress-image-snapshot/plugin')
 | 
			
		||||
 | 
			
		||||
module.exports = (on, config) => {
 | 
			
		||||
	addMatchImageSnapshotPlugin(on, config)
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -1,6 +1,7 @@
 | 
			
		|||
#!/usr/bin/env bash
 | 
			
		||||
# RUN THIS SCRIPT FROM THE ROOT FOLDER OF YOUR APP
 | 
			
		||||
APP_NAME=${PWD##*/}
 | 
			
		||||
CYPRESS_baseUrl=http://127.0.0.1:8082/index.php
 | 
			
		||||
 | 
			
		||||
if [[ $APP_NAME == "cypress" ]]
 | 
			
		||||
then
 | 
			
		||||
| 
						 | 
				
			
			@ -8,13 +9,11 @@ then
 | 
			
		|||
else
 | 
			
		||||
	echo "Launching docker server for the $APP_NAME app"
 | 
			
		||||
	cd cypress
 | 
			
		||||
	docker-compose up -d
 | 
			
		||||
	echo -n "Waiting for server start "
 | 
			
		||||
	until [[ $(docker-compose exec -u www-data -T nextcloud php ./occ status --output=json) == *"\"installed\":true"* ]]
 | 
			
		||||
	do
 | 
			
		||||
	  echo -n "."
 | 
			
		||||
  done
 | 
			
		||||
  echo ""
 | 
			
		||||
	docker-compose pull
 | 
			
		||||
	docker-compose up -d --force-recreate
 | 
			
		||||
	npm run wait-on $CYPRESS_baseUrl
 | 
			
		||||
	echo "Nextcloud successfully installed"
 | 
			
		||||
	docker-compose exec --env APP_NAME=$APP_NAME -T nextcloud bash /initserver.sh
 | 
			
		||||
  docker-compose exec -u www-data -T nextcloud php ./occ social:reset -n
 | 
			
		||||
	docker-compose exec -u www-data -T nextcloud php ./occ social:reset -n
 | 
			
		||||
	echo "Nextcloud successfully configured"
 | 
			
		||||
fi
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -20,37 +20,45 @@
 | 
			
		|||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
import { addMatchImageSnapshotCommand } from 'cypress-image-snapshot/command'
 | 
			
		||||
import axios from '@nextcloud/axios'
 | 
			
		||||
 | 
			
		||||
addMatchImageSnapshotCommand()
 | 
			
		||||
 | 
			
		||||
const url = Cypress.config('baseUrl').replace(/\/index.php\/?$/g, '')
 | 
			
		||||
Cypress.env('baseUrl', url)
 | 
			
		||||
 | 
			
		||||
Cypress.Commands.add('login', (user, password, route = '/apps/files') => {
 | 
			
		||||
	cy.clearCookies();
 | 
			
		||||
	Cypress.Cookies.defaults({
 | 
			
		||||
		preserve: /^(oc|nc)/,
 | 
			
		||||
	})
 | 
			
		||||
	cy.visit(route)
 | 
			
		||||
	cy.get('input[name=user]').type(user)
 | 
			
		||||
	cy.get('input[name=password]').type(password)
 | 
			
		||||
	cy.get('#submit-wrapper input[type=submit]').click()
 | 
			
		||||
	cy.get('form[name=login] [type=submit]').click()
 | 
			
		||||
	cy.url().should('include', route)
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
Cypress.Commands.add('logout', () => {
 | 
			
		||||
	if (Cypress.$("input[name=user]").length > 0) {
 | 
			
		||||
		// already logged out
 | 
			
		||||
	} else {
 | 
			
		||||
		cy.get('#expanddiv li[data-id="logout"] a').then(logout => {
 | 
			
		||||
			if (logout) {
 | 
			
		||||
				cy.visit(logout[0].href)
 | 
			
		||||
	cy.getCookies()
 | 
			
		||||
		.then(cookies => {
 | 
			
		||||
			if (cookies.length === 0) {
 | 
			
		||||
				cy.log('Not logged, skipping logout...')
 | 
			
		||||
				return
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return cy.get('body')
 | 
			
		||||
				.then($body => {
 | 
			
		||||
					const $settingsButton = $body.find('#settings #expand')
 | 
			
		||||
					if ($settingsButton.length === 0) {
 | 
			
		||||
						cy.log('Not logged in.')
 | 
			
		||||
						return
 | 
			
		||||
					}
 | 
			
		||||
 | 
			
		||||
					$settingsButton.click()
 | 
			
		||||
					cy.contains('Log out').click()
 | 
			
		||||
				})
 | 
			
		||||
		})
 | 
			
		||||
	}
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
Cypress.Commands.add('nextcloudCreateUser', (user, password) => {
 | 
			
		||||
	cy.clearCookies();
 | 
			
		||||
	cy.request({
 | 
			
		||||
		method: 'POST',
 | 
			
		||||
		url: `${Cypress.env('baseUrl')}/ocs/v1.php/cloud/users?format=json`,
 | 
			
		||||
| 
						 | 
				
			
			@ -61,13 +69,12 @@ Cypress.Commands.add('nextcloudCreateUser', (user, password) => {
 | 
			
		|||
		},
 | 
			
		||||
		auth: { user: 'admin', pass: 'admin' },
 | 
			
		||||
		headers: {
 | 
			
		||||
			'OCS-ApiRequest': 'true',
 | 
			
		||||
			'Content-Type': 'application/x-www-form-urlencoded',
 | 
			
		||||
			Authorization: `Basic ${btoa('admin:admin')}`,
 | 
			
		||||
			'OCS-ApiRequest': 'true',
 | 
			
		||||
			Authorization: `Basic ${Buffer.from('admin:admin').toString('base64')}`,
 | 
			
		||||
		},
 | 
			
		||||
	}).then(response => {
 | 
			
		||||
		cy.log(`Created user ${user}`, response.status)
 | 
			
		||||
	})
 | 
			
		||||
	cy.clearCookies()
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
Cypress.Commands.add('uploadFile', (fileName, mimeType, path = '') => {
 | 
			
		||||
| 
						 | 
				
			
			@ -82,7 +89,7 @@ Cypress.Commands.add('uploadFile', (fileName, mimeType, path = '') => {
 | 
			
		|||
					headers: {
 | 
			
		||||
						requesttoken: window.OC.requestToken,
 | 
			
		||||
						'Content-Type': mimeType,
 | 
			
		||||
					}
 | 
			
		||||
					},
 | 
			
		||||
				}).then(response => {
 | 
			
		||||
					cy.log(`Uploaded ${fileName}`, response)
 | 
			
		||||
				})
 | 
			
		||||
| 
						 | 
				
			
			@ -122,7 +129,7 @@ Cypress.Commands.add('deleteFile', fileName => {
 | 
			
		|||
 * Create a share link and return the share url
 | 
			
		||||
 *
 | 
			
		||||
 * @param {string} path the file/folder path
 | 
			
		||||
 * @returns {string} the share link url
 | 
			
		||||
 * @return {string} the share link url
 | 
			
		||||
 */
 | 
			
		||||
Cypress.Commands.add('createLinkShare', path => {
 | 
			
		||||
	return cy.window().then(async window => {
 | 
			
		||||
| 
						 | 
				
			
			@ -133,26 +140,15 @@ Cypress.Commands.add('createLinkShare', path => {
 | 
			
		|||
			}, {
 | 
			
		||||
				headers: {
 | 
			
		||||
					requesttoken: window.OC.requestToken,
 | 
			
		||||
				}
 | 
			
		||||
				},
 | 
			
		||||
			})
 | 
			
		||||
			if (!('ocs' in request.data) || !('token' in request.data.ocs.data && request.data.ocs.data.token.length > 0)) {
 | 
			
		||||
				throw request
 | 
			
		||||
			}
 | 
			
		||||
			cy.log('Share link created', request.data.ocs.data.token)
 | 
			
		||||
			return cy.wrap(request.data.ocs.data.token)
 | 
			
		||||
		} catch(error) {
 | 
			
		||||
		} catch (error) {
 | 
			
		||||
			console.error(error)
 | 
			
		||||
		}
 | 
			
		||||
	}).should('have.length', 15)
 | 
			
		||||
})
 | 
			
		||||
 | 
			
		||||
Cypress.Commands.overwrite('matchImageSnapshot', (originalFn, subject, name, options) => {
 | 
			
		||||
	// hide avatar because random colour break the visual regression tests
 | 
			
		||||
	cy.window().then(window => {
 | 
			
		||||
		const avatarDiv = window.document.querySelector('.avatardiv')
 | 
			
		||||
		if (avatarDiv) {
 | 
			
		||||
			avatarDiv.remove()
 | 
			
		||||
		}
 | 
			
		||||
	})
 | 
			
		||||
	return originalFn(subject, name, options)
 | 
			
		||||
})
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,5 +1,5 @@
 | 
			
		|||
// ***********************************************************
 | 
			
		||||
// This example support/index.js is processed and
 | 
			
		||||
// This example support/e2e.js is processed and
 | 
			
		||||
// loaded automatically before your test files.
 | 
			
		||||
//
 | 
			
		||||
// This is a great place to put global configuration and
 | 
			
		||||
| 
						 | 
				
			
			@ -14,7 +14,4 @@
 | 
			
		|||
// ***********************************************************
 | 
			
		||||
 | 
			
		||||
// Import commands.js using ES2015 syntax:
 | 
			
		||||
import './commands'
 | 
			
		||||
 | 
			
		||||
// Alternatively you can use CommonJS syntax:
 | 
			
		||||
// require('./commands')
 | 
			
		||||
import './commands.js'
 | 
			
		||||
| 
						 | 
				
			
			@ -185,7 +185,7 @@ class AP {
 | 
			
		|||
	 */
 | 
			
		||||
	public function getItemFromData(array $data, ACore $parent = null, int $level = 0): ACore {
 | 
			
		||||
		if (++$level > self::REDUNDANCY_LIMIT) {
 | 
			
		||||
			throw new RedundancyLimitException($level);
 | 
			
		||||
			throw new RedundancyLimitException((string)$level);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$item = $this->getSimpleItemFromData($data);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -50,7 +50,6 @@ use OCA\Social\Service\StreamQueueService;
 | 
			
		|||
use OCA\Social\Service\StreamService;
 | 
			
		||||
use OCA\Social\Tools\Traits\TAsync;
 | 
			
		||||
use OCA\Social\Tools\Traits\TNCDataResponse;
 | 
			
		||||
use OCA\Social\Tools\Traits\TNCLogger;
 | 
			
		||||
use OCA\Social\Tools\Traits\TStringTools;
 | 
			
		||||
use OCP\AppFramework\Controller;
 | 
			
		||||
use OCP\AppFramework\Http;
 | 
			
		||||
| 
						 | 
				
			
			@ -63,7 +62,6 @@ class ActivityPubController extends Controller {
 | 
			
		|||
	use TNCDataResponse;
 | 
			
		||||
	use TStringTools;
 | 
			
		||||
	use TAsync;
 | 
			
		||||
	use TNCLogger;
 | 
			
		||||
 | 
			
		||||
	private SocialPubController $socialPubController;
 | 
			
		||||
	private FediverseService $fediverseService;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -12,6 +12,9 @@ use OCP\EventDispatcher\IEventListener;
 | 
			
		|||
use OCP\Profile\BeforeTemplateRenderedEvent;
 | 
			
		||||
use OCP\Util;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * @template-implements IEventListener<\OCP\EventDispatcher\Event>
 | 
			
		||||
 */
 | 
			
		||||
class ProfileSectionListener implements IEventListener {
 | 
			
		||||
	public function handle(Event $event): void {
 | 
			
		||||
		if (!($event instanceof BeforeTemplateRenderedEvent)) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -70,17 +70,12 @@ class ACore extends Item implements JsonSerializable {
 | 
			
		|||
	private $parent = null;
 | 
			
		||||
 | 
			
		||||
	private string $requestToken = '';
 | 
			
		||||
 | 
			
		||||
	private array $entries = [];
 | 
			
		||||
 | 
			
		||||
	private ?\OCA\Social\Model\ActivityPub\ACore $object = null;
 | 
			
		||||
 | 
			
		||||
	private ?ACore $object = null;
 | 
			
		||||
	private ?Document $icon = null;
 | 
			
		||||
 | 
			
		||||
	private bool $displayW3ContextSecurity = false;
 | 
			
		||||
 | 
			
		||||
	private ?LinkedDataSignature $signature = null;
 | 
			
		||||
 | 
			
		||||
	private int $format = self::FORMAT_ACTIVITYPUB;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -151,9 +146,9 @@ class ACore extends Item implements JsonSerializable {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return ACore
 | 
			
		||||
	 * @return null|self
 | 
			
		||||
	 */
 | 
			
		||||
	public function getObject(): ACore {
 | 
			
		||||
	public function getObject(): ?ACore {
 | 
			
		||||
		return $this->object;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -162,7 +157,7 @@ class ACore extends Item implements JsonSerializable {
 | 
			
		|||
	 *
 | 
			
		||||
	 * @return ACore
 | 
			
		||||
	 */
 | 
			
		||||
	public function setObject(ACore &$object): ACore {
 | 
			
		||||
	public function setObject(ACore $object): self {
 | 
			
		||||
		$object->setParent($this);
 | 
			
		||||
		$this->object = $object;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -205,10 +200,7 @@ class ACore extends Item implements JsonSerializable {
 | 
			
		|||
		return ($this->icon !== null);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return Document
 | 
			
		||||
	 */
 | 
			
		||||
	public function getIcon(): Document {
 | 
			
		||||
	public function getIcon(): ?Document {
 | 
			
		||||
		return $this->icon;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -217,7 +209,7 @@ class ACore extends Item implements JsonSerializable {
 | 
			
		|||
	 *
 | 
			
		||||
	 * @return ACore
 | 
			
		||||
	 */
 | 
			
		||||
	public function setIcon(Document &$icon): ACore {
 | 
			
		||||
	public function setIcon(Document $icon): ACore {
 | 
			
		||||
		$icon->setParent($this);
 | 
			
		||||
		$this->icon = $icon;
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -255,14 +247,11 @@ class ACore extends Item implements JsonSerializable {
 | 
			
		|||
	/**
 | 
			
		||||
	 * @return bool
 | 
			
		||||
	 */
 | 
			
		||||
	public function gotSignature(): bool {
 | 
			
		||||
	public function hasSignature(): bool {
 | 
			
		||||
		return ($this->signature !== null);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return LinkedDataSignature
 | 
			
		||||
	 */
 | 
			
		||||
	public function getSignature(): LinkedDataSignature {
 | 
			
		||||
	public function getSignature(): ?LinkedDataSignature {
 | 
			
		||||
		return $this->signature;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -694,14 +683,14 @@ class ACore extends Item implements JsonSerializable {
 | 
			
		|||
	 * @return array
 | 
			
		||||
	 */
 | 
			
		||||
	public function exportAsActivityPub(): array {
 | 
			
		||||
		if ($this->gotSignature()) {
 | 
			
		||||
		if ($this->hasSignature()) {
 | 
			
		||||
			$this->entries['signature'] = $this->getSignature();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ($this->isRoot()) {
 | 
			
		||||
			$context = [self::CONTEXT_ACTIVITYSTREAMS];
 | 
			
		||||
 | 
			
		||||
			if ($this->gotSignature() || $this->isDisplayW3ContextSecurity()) {
 | 
			
		||||
			if ($this->hasSignature() || $this->isDisplayW3ContextSecurity()) {
 | 
			
		||||
				array_push($context, self::CONTEXT_SECURITY);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -228,10 +228,7 @@ class Instance implements IQueryRow, JsonSerializable {
 | 
			
		|||
		return ($this->contactAccount !== null);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return Person
 | 
			
		||||
	 */
 | 
			
		||||
	public function getContactAccount(): Person {
 | 
			
		||||
	public function getContactAccount(): ?Person {
 | 
			
		||||
		return $this->contactAccount;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -158,10 +158,7 @@ class RequestQueue implements JsonSerializable {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return InstancePath
 | 
			
		||||
	 */
 | 
			
		||||
	public function getInstance(): InstancePath {
 | 
			
		||||
	public function getInstance(): ?InstancePath {
 | 
			
		||||
		return $this->instance;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,7 +30,6 @@ declare(strict_types=1);
 | 
			
		|||
 | 
			
		||||
namespace OCA\Social\Search;
 | 
			
		||||
 | 
			
		||||
use OCA\Social\Tools\Traits\TNCLogger;
 | 
			
		||||
use OCA\Social\Tools\Traits\TArrayTools;
 | 
			
		||||
use Exception;
 | 
			
		||||
use OCA\Social\Exceptions\AccountDoesNotExistException;
 | 
			
		||||
| 
						 | 
				
			
			@ -58,30 +57,17 @@ class UnifiedSearchProvider implements IProvider {
 | 
			
		|||
	public const PROVIDER_ID = 'social';
 | 
			
		||||
	public const ORDER = 12;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	use TArrayTools;
 | 
			
		||||
	use TNCLogger;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	private IL10N $l10n;
 | 
			
		||||
 | 
			
		||||
	private IURLGenerator $urlGenerator;
 | 
			
		||||
 | 
			
		||||
	private StreamService $streamService;
 | 
			
		||||
 | 
			
		||||
	private FollowService $followService;
 | 
			
		||||
 | 
			
		||||
	private CacheActorService $cacheActorService;
 | 
			
		||||
 | 
			
		||||
	private AccountService $accountService;
 | 
			
		||||
 | 
			
		||||
	private SearchService $searchService;
 | 
			
		||||
 | 
			
		||||
	private ConfigService $configService;
 | 
			
		||||
 | 
			
		||||
	private MiscService $miscService;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	private ?Person $viewer = null;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -30,14 +30,6 @@ declare(strict_types=1);
 | 
			
		|||
 | 
			
		||||
namespace OCA\Social\Service;
 | 
			
		||||
 | 
			
		||||
use OCA\Social\Tools\Exceptions\MalformedArrayException;
 | 
			
		||||
use OCA\Social\Tools\Exceptions\RequestContentException;
 | 
			
		||||
use OCA\Social\Tools\Exceptions\RequestNetworkException;
 | 
			
		||||
use OCA\Social\Tools\Exceptions\RequestResultNotJsonException;
 | 
			
		||||
use OCA\Social\Tools\Exceptions\RequestResultSizeException;
 | 
			
		||||
use OCA\Social\Tools\Exceptions\RequestServerException;
 | 
			
		||||
use OCA\Social\Tools\Traits\TNCLogger;
 | 
			
		||||
use OCA\Social\Tools\Traits\TArrayTools;
 | 
			
		||||
use Exception;
 | 
			
		||||
use OCA\Social\AP;
 | 
			
		||||
use OCA\Social\Db\CacheActorsRequest;
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +43,15 @@ use OCA\Social\Exceptions\RetrieveAccountFormatException;
 | 
			
		|||
use OCA\Social\Exceptions\SocialAppConfigException;
 | 
			
		||||
use OCA\Social\Exceptions\UnauthorizedFediverseException;
 | 
			
		||||
use OCA\Social\Model\ActivityPub\Actor\Person;
 | 
			
		||||
use OCA\Social\Tools\Exceptions\MalformedArrayException;
 | 
			
		||||
use OCA\Social\Tools\Exceptions\RequestContentException;
 | 
			
		||||
use OCA\Social\Tools\Exceptions\RequestNetworkException;
 | 
			
		||||
use OCA\Social\Tools\Exceptions\RequestResultNotJsonException;
 | 
			
		||||
use OCA\Social\Tools\Exceptions\RequestResultSizeException;
 | 
			
		||||
use OCA\Social\Tools\Exceptions\RequestServerException;
 | 
			
		||||
use OCA\Social\Tools\Traits\TArrayTools;
 | 
			
		||||
use OCP\IURLGenerator;
 | 
			
		||||
use Psr\Log\LoggerInterface;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class CacheActorService
 | 
			
		||||
| 
						 | 
				
			
			@ -60,28 +60,31 @@ use OCP\IURLGenerator;
 | 
			
		|||
 */
 | 
			
		||||
class CacheActorService {
 | 
			
		||||
	use TArrayTools;
 | 
			
		||||
	use TNCLogger;
 | 
			
		||||
 | 
			
		||||
	private \OCP\IURLGenerator $urlGenerator;
 | 
			
		||||
	private CacheActorsRequest $cacheActorsRequest;
 | 
			
		||||
	private CurlService $curlService;
 | 
			
		||||
	private FediverseService $fediverseService;
 | 
			
		||||
	private ConfigService $configService;
 | 
			
		||||
	private MiscService $miscService;
 | 
			
		||||
	private LoggerInterface $logger;
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * CacheService constructor.
 | 
			
		||||
	 * CacheActorService constructor.
 | 
			
		||||
	 */
 | 
			
		||||
	public function __construct(
 | 
			
		||||
		IUrlGenerator $urlGenerator, CacheActorsRequest $cacheActorsRequest, CurlService $curlService,
 | 
			
		||||
		FediverseService $fediverseService, ConfigService $configService, MiscService $miscService
 | 
			
		||||
		IUrlGenerator $urlGenerator,
 | 
			
		||||
		CacheActorsRequest $cacheActorsRequest,
 | 
			
		||||
		CurlService $curlService,
 | 
			
		||||
		FediverseService $fediverseService,
 | 
			
		||||
		ConfigService $configService,
 | 
			
		||||
		LoggerInterface $logger
 | 
			
		||||
	) {
 | 
			
		||||
		$this->urlGenerator = $urlGenerator;
 | 
			
		||||
		$this->cacheActorsRequest = $cacheActorsRequest;
 | 
			
		||||
		$this->curlService = $curlService;
 | 
			
		||||
		$this->fediverseService = $fediverseService;
 | 
			
		||||
		$this->configService = $configService;
 | 
			
		||||
		$this->miscService = $miscService;
 | 
			
		||||
		$this->logger = $logger;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -127,7 +130,7 @@ class CacheActorService {
 | 
			
		|||
		} catch (CacheActorDoesNotExistException $e) {
 | 
			
		||||
			$object = $this->curlService->retrieveObject($id);
 | 
			
		||||
 | 
			
		||||
			$this->debug('object retrieved', ['id' => $id, 'object' => $object]);
 | 
			
		||||
			$this->logger->debug('object retrieved', ['id' => $id, 'object' => $object]);
 | 
			
		||||
 | 
			
		||||
			/** @var Person $actor */
 | 
			
		||||
			$actor = AP::$activityPub->getItemFromData($object);
 | 
			
		||||
| 
						 | 
				
			
			@ -205,14 +208,14 @@ class CacheActorService {
 | 
			
		|||
		} catch (CacheActorDoesNotExistException $e) {
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$this->debug('getFromAccount', ['account' => $account, 'retrieve' => $retrieve]);
 | 
			
		||||
		$this->logger->debug('getFromAccount', ['account' => $account, 'retrieve' => $retrieve]);
 | 
			
		||||
 | 
			
		||||
		try {
 | 
			
		||||
			$actor = $this->cacheActorsRequest->getFromAccount($account);
 | 
			
		||||
 | 
			
		||||
			$this->debug('Found Actor', ['account' => $account, 'actor' => $actor]);
 | 
			
		||||
			$this->logger->debug('Found Actor', ['account' => $account, 'actor' => $actor]);
 | 
			
		||||
		} catch (CacheActorDoesNotExistException $e) {
 | 
			
		||||
			$this->debug('Actor not found', ['account' => $account]);
 | 
			
		||||
			$this->logger->debug('Actor not found', ['account' => $account]);
 | 
			
		||||
 | 
			
		||||
			if (!$retrieve) {
 | 
			
		||||
				throw new CacheActorDoesNotExistException();
 | 
			
		||||
| 
						 | 
				
			
			@ -221,7 +224,7 @@ class CacheActorService {
 | 
			
		|||
			$actor = $this->curlService->retrieveAccount($account);
 | 
			
		||||
			$actor->setAccount($account);
 | 
			
		||||
			try {
 | 
			
		||||
				$this->warning('Saving Actor', false, ['actor' => $actor]);
 | 
			
		||||
				$this->logger->debug('Saving Actor', ['actor' => $actor]);
 | 
			
		||||
 | 
			
		||||
				$this->save($actor);
 | 
			
		||||
			} catch (Exception $e) {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -203,16 +203,19 @@ class CacheDocumentService {
 | 
			
		|||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param $content
 | 
			
		||||
	 * @param string $content
 | 
			
		||||
	 */
 | 
			
		||||
	private function resizeImage(&$content) {
 | 
			
		||||
	private function resizeImage(string &$content) {
 | 
			
		||||
		try {
 | 
			
		||||
			$image = ImageResize::createFromString($content);
 | 
			
		||||
			$image->quality_jpg = 100;
 | 
			
		||||
			$image->quality_png = 9;
 | 
			
		||||
 | 
			
		||||
			$image->resizeToBestFit(self::RESIZED_WIDTH, self::RESIZED_HEIGHT);
 | 
			
		||||
			$content = $image->getImageAsString();
 | 
			
		||||
			$newContent = $image->getImageAsString();
 | 
			
		||||
			if (!$newContent) {
 | 
			
		||||
				$content = $newContent;
 | 
			
		||||
			}
 | 
			
		||||
		} catch (ImageResizeException $e) {
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -276,8 +276,10 @@ class ConfigService {
 | 
			
		|||
	 * @param $key
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return mixed
 | 
			
		||||
	 *
 | 
			
		||||
	 * @psalm-param string $key
 | 
			
		||||
	 */
 | 
			
		||||
	public function getSystemValue($key) {
 | 
			
		||||
	public function getSystemValue(string $key) {
 | 
			
		||||
		return $this->config->getSystemValue($key, '');
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -238,7 +238,7 @@ class CurlService {
 | 
			
		|||
	 * @throws SocialAppConfigException
 | 
			
		||||
	 * @throws UnauthorizedFediverseException
 | 
			
		||||
	 */
 | 
			
		||||
	public function retrieveObject($id): array {
 | 
			
		||||
	public function retrieveObject(string $id): array {
 | 
			
		||||
		$this->logger->debug('retrieveObject id=' . $id);
 | 
			
		||||
		$url = parse_url($id);
 | 
			
		||||
		$this->mustContains(['path', 'host', 'scheme'], $url);
 | 
			
		||||
| 
						 | 
				
			
			@ -430,8 +430,6 @@ class CurlService {
 | 
			
		|||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param Request $request
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return resource
 | 
			
		||||
	 */
 | 
			
		||||
	private function generateCurlRequest(Request $request) {
 | 
			
		||||
		$url = $request->getUsedProtocol() . '://' . $request->getHost() . $request->getParsedUrl();
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -232,7 +232,9 @@ class FollowService {
 | 
			
		|||
	/**
 | 
			
		||||
	 * @param Person $actor
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return Person[]
 | 
			
		||||
	 * @return Follow[]
 | 
			
		||||
	 *
 | 
			
		||||
	 * @psalm-return array<Follow>
 | 
			
		||||
	 */
 | 
			
		||||
	public function getFollowers(Person $actor): array {
 | 
			
		||||
		return $this->followsRequest->getFollowersByActorId($actor->getId());
 | 
			
		||||
| 
						 | 
				
			
			@ -257,7 +259,9 @@ class FollowService {
 | 
			
		|||
	/**
 | 
			
		||||
	 * @param Person $actor
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return Person[]
 | 
			
		||||
	 * @return Follow[]
 | 
			
		||||
	 *
 | 
			
		||||
	 * @psalm-return array<Follow>
 | 
			
		||||
	 */
 | 
			
		||||
	public function getFollowing(Person $actor): array {
 | 
			
		||||
		return $this->followsRequest->getFollowingByActorId($actor->getId());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -39,7 +39,6 @@ use OCA\Social\Exceptions\HashtagDoesNotExistException;
 | 
			
		|||
use OCA\Social\Exceptions\ItemUnknownException;
 | 
			
		||||
use OCA\Social\Exceptions\SocialAppConfigException;
 | 
			
		||||
use OCA\Social\Model\ActivityPub\Object\Note;
 | 
			
		||||
use OCA\Social\Model\ActivityPub\Stream;
 | 
			
		||||
 | 
			
		||||
class HashtagService {
 | 
			
		||||
	public const TREND_1H = 3600;
 | 
			
		||||
| 
						 | 
				
			
			@ -155,10 +154,9 @@ class HashtagService {
 | 
			
		|||
	/**
 | 
			
		||||
	 * @param int $timestamp
 | 
			
		||||
	 *
 | 
			
		||||
	 * @return Stream[]
 | 
			
		||||
	 * @return int[]
 | 
			
		||||
	 * @throws DateTimeException
 | 
			
		||||
	 * @throws ItemUnknownException
 | 
			
		||||
	 * @throws SocialAppConfigException
 | 
			
		||||
	 * @psalm-return array<int>
 | 
			
		||||
	 */
 | 
			
		||||
	private function getTrendSince(int $timestamp): array {
 | 
			
		||||
		$result = [];
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -58,7 +58,7 @@ class MiscService {
 | 
			
		|||
	 * @param $message
 | 
			
		||||
	 * @param int $level
 | 
			
		||||
	 */
 | 
			
		||||
	public function log($message, $level = 2) {
 | 
			
		||||
	public function log(string $message, $level = 2) {
 | 
			
		||||
		$data = array(
 | 
			
		||||
			'app' => Application::APP_NAME,
 | 
			
		||||
			'level' => $level
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -97,7 +97,7 @@ class PostService {
 | 
			
		|||
	 * @throws StreamNotFoundException
 | 
			
		||||
	 * @throws UnauthorizedFediverseException
 | 
			
		||||
	 */
 | 
			
		||||
	public function createPost(Post $post, string &$token = ''): ACore {
 | 
			
		||||
	public function createPost(Post $post, string &$token = ''): ?ACore {
 | 
			
		||||
		$this->fixRecipientAndHashtags($post);
 | 
			
		||||
 | 
			
		||||
		$note = new Note();
 | 
			
		||||
| 
						 | 
				
			
			@ -130,10 +130,10 @@ class PostService {
 | 
			
		|||
	private function generateDocumentsFromAttachments(Note $note, Post $post) {
 | 
			
		||||
		$documents = [];
 | 
			
		||||
		if (!isset($_FILES['attachments'])) {
 | 
			
		||||
			return [];
 | 
			
		||||
			return;
 | 
			
		||||
		}
 | 
			
		||||
		if (is_array($_FILES["attachments"]["error"])) {
 | 
			
		||||
			foreach ($_FILES["attachments"]["error"] as $key => $error) {
 | 
			
		||||
		if (is_array($_FILES['attachments']['error'])) {
 | 
			
		||||
			foreach ($_FILES['attachments']['error'] as $key => $error) {
 | 
			
		||||
				if ($error == UPLOAD_ERR_OK) {
 | 
			
		||||
					try {
 | 
			
		||||
						$document = $this->generateDocumentFromAttachment($note, $key);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -31,10 +31,10 @@ declare(strict_types=1);
 | 
			
		|||
 | 
			
		||||
namespace OCA\Social\Service;
 | 
			
		||||
 | 
			
		||||
use OCA\Social\Tools\Traits\TNCLogger;
 | 
			
		||||
use OCA\Social\Tools\Traits\TArrayTools;
 | 
			
		||||
use Exception;
 | 
			
		||||
use OCA\Social\Model\ActivityPub\Actor\Person;
 | 
			
		||||
use OCA\Social\Tools\Traits\TArrayTools;
 | 
			
		||||
use Psr\Log\LoggerInterface;
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Class SearchService
 | 
			
		||||
| 
						 | 
				
			
			@ -43,7 +43,6 @@ use OCA\Social\Model\ActivityPub\Actor\Person;
 | 
			
		|||
 */
 | 
			
		||||
class SearchService {
 | 
			
		||||
	use TArrayTools;
 | 
			
		||||
	use TNCLogger;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public const SEARCH_ACCOUNTS = 1;
 | 
			
		||||
| 
						 | 
				
			
			@ -51,14 +50,10 @@ class SearchService {
 | 
			
		|||
	public const SEARCH_CONTENT = 4;
 | 
			
		||||
	public const SEARCH_ALL = 7;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	private CacheActorService $cacheActorService;
 | 
			
		||||
 | 
			
		||||
	private HashtagService $hashtagService;
 | 
			
		||||
 | 
			
		||||
	private ConfigService $configService;
 | 
			
		||||
 | 
			
		||||
	private MiscService $miscService;
 | 
			
		||||
	private LoggerInterface $logger;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
| 
						 | 
				
			
			@ -67,16 +62,18 @@ class SearchService {
 | 
			
		|||
	 * @param CacheActorService $cacheActorService
 | 
			
		||||
	 * @param HashtagService $hashtagService
 | 
			
		||||
	 * @param ConfigService $configService
 | 
			
		||||
	 * @param MiscService $miscService
 | 
			
		||||
	 * @param LoggerInterface $logger
 | 
			
		||||
	 */
 | 
			
		||||
	public function __construct(
 | 
			
		||||
		CacheActorService $cacheActorService, HashtagService $hashtagService,
 | 
			
		||||
		ConfigService $configService, MiscService $miscService
 | 
			
		||||
		CacheActorService $cacheActorService,
 | 
			
		||||
		HashtagService $hashtagService,
 | 
			
		||||
		ConfigService $configService,
 | 
			
		||||
		LoggerInterface $logger
 | 
			
		||||
	) {
 | 
			
		||||
		$this->cacheActorService = $cacheActorService;
 | 
			
		||||
		$this->hashtagService = $hashtagService;
 | 
			
		||||
		$this->configService = $configService;
 | 
			
		||||
		$this->miscService = $miscService;
 | 
			
		||||
		$this->logger = $logger;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
| 
						 | 
				
			
			@ -100,7 +97,7 @@ class SearchService {
 | 
			
		|||
		try {
 | 
			
		||||
			$this->cacheActorService->getFromAccount($search);
 | 
			
		||||
		} catch (Exception $e) {
 | 
			
		||||
			$this->exception($e, self::$NOTICE, ['search' => $search]);
 | 
			
		||||
			$this->logger->notice('searchAccounts', ['exception' => $e, 'search' => $search]);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		return $this->cacheActorService->searchCachedAccounts($search);
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -451,7 +451,7 @@ class SignatureService {
 | 
			
		|||
	 *
 | 
			
		||||
	 * @return array
 | 
			
		||||
	 */
 | 
			
		||||
	private function parseSignatureHeader($signatureHeader) {
 | 
			
		||||
	private function parseSignatureHeader(string $signatureHeader) {
 | 
			
		||||
		$sign = [];
 | 
			
		||||
 | 
			
		||||
		$entries = explode(',', $signatureHeader);
 | 
			
		||||
| 
						 | 
				
			
			@ -504,7 +504,7 @@ class SignatureService {
 | 
			
		|||
	 * @return string
 | 
			
		||||
	 * @throws InvalidOriginException
 | 
			
		||||
	 */
 | 
			
		||||
	private function getKeyOrigin($id) {
 | 
			
		||||
	private function getKeyOrigin(string $id) {
 | 
			
		||||
		$host = parse_url($id, PHP_URL_HOST);
 | 
			
		||||
		if (is_string($host) && ($host !== '')) {
 | 
			
		||||
			return $host;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -544,7 +544,7 @@ class StreamService {
 | 
			
		|||
	 * @throws RequestResultNotJsonException
 | 
			
		||||
	 * @throws UnauthorizedFediverseException
 | 
			
		||||
	 */
 | 
			
		||||
	public function getAuthorFromPostId($noteId) {
 | 
			
		||||
	public function getAuthorFromPostId(string $noteId) {
 | 
			
		||||
		$note = $this->streamRequest->getStreamById($noteId);
 | 
			
		||||
 | 
			
		||||
		return $this->cacheActorService->getFromId($note->getAttributedTo());
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -455,7 +455,10 @@ class Request implements JsonSerializable {
 | 
			
		|||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	public function addHeader($key, $value): Request {
 | 
			
		||||
	/**
 | 
			
		||||
	 * @psalm-param string $key
 | 
			
		||||
	 */
 | 
			
		||||
	public function addHeader(string $key, string $value): Request {
 | 
			
		||||
		$header = $this->get($key, $this->headers);
 | 
			
		||||
		if ($header !== '') {
 | 
			
		||||
			$header .= ', ' . $value;
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,200 +0,0 @@
 | 
			
		|||
<?php
 | 
			
		||||
 | 
			
		||||
declare(strict_types=1);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Some tools for myself.
 | 
			
		||||
 *
 | 
			
		||||
 * This file is licensed under the Affero General Public License version 3 or
 | 
			
		||||
 * later. See the COPYING file.
 | 
			
		||||
 *
 | 
			
		||||
 * @author Maxence Lange <maxence@artificial-owl.com>
 | 
			
		||||
 * @copyright 2020, Maxence Lange <maxence@artificial-owl.com>
 | 
			
		||||
 * @license GNU AGPL version 3 or any later version
 | 
			
		||||
 *
 | 
			
		||||
 * This program is free software: you can redistribute it and/or modify
 | 
			
		||||
 * it under the terms of the GNU Affero General Public License as
 | 
			
		||||
 * published by the Free Software Foundation, either version 3 of the
 | 
			
		||||
 * License, or (at your option) any later version.
 | 
			
		||||
 *
 | 
			
		||||
 * This program is distributed in the hope that it will be useful,
 | 
			
		||||
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
			
		||||
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 | 
			
		||||
 * GNU Affero General Public License for more details.
 | 
			
		||||
 *
 | 
			
		||||
 * You should have received a copy of the GNU Affero General Public License
 | 
			
		||||
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 | 
			
		||||
 *
 | 
			
		||||
 */
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
namespace OCA\Social\Tools\Traits;
 | 
			
		||||
 | 
			
		||||
use Exception;
 | 
			
		||||
use OC\HintException;
 | 
			
		||||
use OCP\Server;
 | 
			
		||||
use Psr\Log\LoggerInterface;
 | 
			
		||||
use Throwable;
 | 
			
		||||
 | 
			
		||||
trait TNCLogger {
 | 
			
		||||
	use TNCSetup;
 | 
			
		||||
 | 
			
		||||
	public static int $EMERGENCY = 4;
 | 
			
		||||
	public static int $ALERT = 3;
 | 
			
		||||
	public static int $CRITICAL = 3;
 | 
			
		||||
	public static int $ERROR = 3;
 | 
			
		||||
	public static int $WARNING = 2;
 | 
			
		||||
	public static int $NOTICE = 1;
 | 
			
		||||
	public static int $INFO = 1;
 | 
			
		||||
	public static int $DEBUG = 0;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param Throwable $t
 | 
			
		||||
	 * @param array $serializable
 | 
			
		||||
	 */
 | 
			
		||||
	public function t(Throwable $t, array $serializable = []): void {
 | 
			
		||||
		$this->throwable($t, self::$ERROR, $serializable);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param Throwable $t
 | 
			
		||||
	 * @param int $level
 | 
			
		||||
	 * @param array $serializable
 | 
			
		||||
	 */
 | 
			
		||||
	public function throwable(Throwable $t, int $level = 3, array $serializable = []): void {
 | 
			
		||||
		$message = '';
 | 
			
		||||
		if (!empty($serializable)) {
 | 
			
		||||
			$message = json_encode($serializable);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$this->logger()
 | 
			
		||||
			 ->log(
 | 
			
		||||
			 	$level,
 | 
			
		||||
			 	$message,
 | 
			
		||||
			 	[
 | 
			
		||||
			 		'app' => $this->setup('app'),
 | 
			
		||||
			 		'exception' => $t
 | 
			
		||||
			 	]
 | 
			
		||||
			 );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param Exception $e
 | 
			
		||||
	 * @param array $serializable
 | 
			
		||||
	 */
 | 
			
		||||
	public function e(Exception $e, array $serializable = []): void {
 | 
			
		||||
		$this->exception($e, self::$ERROR, $serializable);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param Exception $e
 | 
			
		||||
	 * @param int|array $level
 | 
			
		||||
	 * @param array $serializable
 | 
			
		||||
	 */
 | 
			
		||||
	public function exception(Exception $e, $level = 3, array $serializable = []): void {
 | 
			
		||||
		if (is_array($level) && empty($serializable)) {
 | 
			
		||||
			$serializable = $level;
 | 
			
		||||
			$level = 3;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$message = '';
 | 
			
		||||
		if (!empty($serializable)) {
 | 
			
		||||
			$message = json_encode($serializable);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		if ($level === self::$DEBUG) {
 | 
			
		||||
			$level = (int)$this->appConfig('debug_level');
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$this->logger()
 | 
			
		||||
			 ->log(
 | 
			
		||||
			 	$level,
 | 
			
		||||
			 	$message,
 | 
			
		||||
			 	[
 | 
			
		||||
			 		'app' => $this->setup('app'),
 | 
			
		||||
			 		'exception' => $e
 | 
			
		||||
			 	]
 | 
			
		||||
			 );
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param string $message
 | 
			
		||||
	 * @param bool $trace
 | 
			
		||||
	 * @param array $serializable
 | 
			
		||||
	 */
 | 
			
		||||
	public function emergency(string $message, bool $trace = false, array $serializable = []): void {
 | 
			
		||||
		$this->log(self::$EMERGENCY, '[emergency] ' . $message, $trace, $serializable);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param string $message
 | 
			
		||||
	 * @param bool $trace
 | 
			
		||||
	 * @param array $serializable
 | 
			
		||||
	 */
 | 
			
		||||
	public function alert(string $message, bool $trace = false, array $serializable = []): void {
 | 
			
		||||
		$this->log(self::$ALERT, '[alert] ' . $message, $trace, $serializable);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param string $message
 | 
			
		||||
	 * @param bool $trace
 | 
			
		||||
	 * @param array $serializable
 | 
			
		||||
	 */
 | 
			
		||||
	public function warning(string $message, bool $trace = false, array $serializable = []): void {
 | 
			
		||||
		$this->log(self::$WARNING, '[warning] ' . $message, $trace, $serializable);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param string $message
 | 
			
		||||
	 * @param bool $trace
 | 
			
		||||
	 * @param array $serializable
 | 
			
		||||
	 */
 | 
			
		||||
	public function notice(string $message, bool $trace = false, array $serializable = []): void {
 | 
			
		||||
		$this->log(self::$NOTICE, '[notice] ' . $message, $trace, $serializable);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param string $message
 | 
			
		||||
	 * @param array $serializable
 | 
			
		||||
	 */
 | 
			
		||||
	public function debug(string $message, array $serializable = []): void {
 | 
			
		||||
		$message = '[debug] ' . $message;
 | 
			
		||||
		$debugLevel = (int)$this->appConfig('debug_level');
 | 
			
		||||
		$this->log($debugLevel, $message, ($this->appConfig('debug_trace') === '1'), $serializable);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @param int $level
 | 
			
		||||
	 * @param string $message
 | 
			
		||||
	 * @param bool $trace
 | 
			
		||||
	 * @param array $serializable
 | 
			
		||||
	 */
 | 
			
		||||
	public function log(int $level, string $message, bool $trace = false, array $serializable = []): void {
 | 
			
		||||
		$opts = ['app' => $this->setup('app')];
 | 
			
		||||
		if ($trace) {
 | 
			
		||||
			$opts['exception'] = new HintException($message, json_encode($serializable));
 | 
			
		||||
		} elseif (!empty($serializable)) {
 | 
			
		||||
			$message .= ' -- ' . json_encode($serializable);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		$this->logger()
 | 
			
		||||
			 ->log($level, $message, $opts);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	/**
 | 
			
		||||
	 * @return LoggerInterface
 | 
			
		||||
	 */
 | 
			
		||||
	public function logger(): LoggerInterface {
 | 
			
		||||
		if (isset($this->logger) && $this->logger instanceof LoggerInterface) {
 | 
			
		||||
			return $this->logger;
 | 
			
		||||
		} else {
 | 
			
		||||
			return Server::get(LoggerInterface::class);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
										
											
												Plik diff jest za duży
												Load Diff
											
										
									
								
							
							
								
								
									
										15
									
								
								package.json
								
								
								
								
							
							
						
						
									
										15
									
								
								package.json
								
								
								
								
							| 
						 | 
				
			
			@ -20,12 +20,14 @@
 | 
			
		|||
		"dev": "NODE_ENV=development webpack --config webpack.common.js",
 | 
			
		||||
		"watch": "NODE_ENV=development webpack --progress --watch --config webpack.common.js",
 | 
			
		||||
		"build": "NODE_ENV=production webpack --progress --config webpack.common.js",
 | 
			
		||||
		"serve": "NODE_ENV=development webpack serve --progress --config webpack.common.js",
 | 
			
		||||
		"lint": "eslint --ext .js,.vue src",
 | 
			
		||||
		"lint:fix": "eslint --ext .js,.vue src --fix",
 | 
			
		||||
		"test": "jest",
 | 
			
		||||
		"test:coverage": "jest --coverage",
 | 
			
		||||
		"cypress": "cypress run",
 | 
			
		||||
		"cypress:gui": "cypress open"
 | 
			
		||||
		"cypress": "./cypress/start.sh; cypress run; ./cypress/stop.sh",
 | 
			
		||||
		"cypress:gui": "./cypress/start.sh; cypress open; ./cypress/stop.sh",
 | 
			
		||||
		"wait-on": "wait-on -i 500 -t 300000"
 | 
			
		||||
	},
 | 
			
		||||
	"dependencies": {
 | 
			
		||||
		"@nextcloud/auth": "^2.0.0",
 | 
			
		||||
| 
						 | 
				
			
			@ -40,6 +42,8 @@
 | 
			
		|||
		"@nextcloud/vue": "^7.3.0",
 | 
			
		||||
		"@nextcloud/vue-richtext": "^2.0.4",
 | 
			
		||||
		"he": "^1.2.0",
 | 
			
		||||
		"linkify-plugin-mention": "^4.1.0",
 | 
			
		||||
		"linkify-string": "^4.1.0",
 | 
			
		||||
		"linkifyjs": "^4.0.2",
 | 
			
		||||
		"sass": "^1.57.1",
 | 
			
		||||
		"tributejs": "^5.1.3",
 | 
			
		||||
| 
						 | 
				
			
			@ -69,13 +73,16 @@
 | 
			
		|||
		"npm": "^7.0.0 || ^8.0.0"
 | 
			
		||||
	},
 | 
			
		||||
	"devDependencies": {
 | 
			
		||||
		"@cypress/browserify-preprocessor": "^3.0.2",
 | 
			
		||||
		"@nextcloud/babel-config": "^1.0.0",
 | 
			
		||||
		"@nextcloud/browserslist-config": "^2.3.0",
 | 
			
		||||
		"@nextcloud/eslint-config": "^8.1.4",
 | 
			
		||||
		"@nextcloud/webpack-vue-config": "^5.4.0",
 | 
			
		||||
		"cypress": "^11.2.0",
 | 
			
		||||
		"jest": "^29.3.1",
 | 
			
		||||
		"jest-serializer-vue": "^3.1.0",
 | 
			
		||||
		"vue-template-compiler": "^2.7.10"
 | 
			
		||||
		"vue-template-compiler": "^2.7.10",
 | 
			
		||||
		"wait-on": "^7.0.1"
 | 
			
		||||
	},
 | 
			
		||||
	"jest": {
 | 
			
		||||
		"moduleFileExtensions": [
 | 
			
		||||
| 
						 | 
				
			
			@ -93,4 +100,4 @@
 | 
			
		|||
			"<rootDir>/node_modules/jest-serializer-vue"
 | 
			
		||||
		]
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -120,6 +120,7 @@
 | 
			
		|||
				<div class="emptySpace" />
 | 
			
		||||
				<NcButton :value="currentVisibilityPostLabel"
 | 
			
		||||
					:disabled="!canPost"
 | 
			
		||||
					native-type="submit"
 | 
			
		||||
					type="primary"
 | 
			
		||||
					@click.prevent="createPost">
 | 
			
		||||
					<template #icon>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -78,11 +78,10 @@
 | 
			
		|||
</template>
 | 
			
		||||
 | 
			
		||||
<script>
 | 
			
		||||
// eslint-disable-next-line no-unused-vars
 | 
			
		||||
import * as linkify from 'linkifyjs'
 | 
			
		||||
// eslint-disable-next-line
 | 
			
		||||
import pluginMention from 'linkifyjs/plugins/mention'
 | 
			
		||||
// eslint-disable-next-line
 | 
			
		||||
import 'linkifyjs/string'
 | 
			
		||||
import 'linkify-plugin-mention'
 | 
			
		||||
import 'linkify-string'
 | 
			
		||||
import currentUser from './../mixins/currentUserMixin.js'
 | 
			
		||||
import PostAttachment from './PostAttachment.vue'
 | 
			
		||||
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
 | 
			
		||||
| 
						 | 
				
			
			@ -97,8 +96,6 @@ import moment from '@nextcloud/moment'
 | 
			
		|||
import { generateUrl } from '@nextcloud/router'
 | 
			
		||||
import RichText from '@nextcloud/vue-richtext'
 | 
			
		||||
 | 
			
		||||
pluginMention(linkify)
 | 
			
		||||
 | 
			
		||||
export default {
 | 
			
		||||
	name: 'TimelinePost',
 | 
			
		||||
	components: {
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1,10 +1,5 @@
 | 
			
		|||
<?xml version="1.0" encoding="UTF-8"?>
 | 
			
		||||
<files psalm-version="4.30.0@d0bc6e25d89f649e4f36a534f330f8bb4643dd69">
 | 
			
		||||
  <file src="lib/AP.php">
 | 
			
		||||
    <InvalidScalarArgument occurrences="1">
 | 
			
		||||
      <code>$level</code>
 | 
			
		||||
    </InvalidScalarArgument>
 | 
			
		||||
  </file>
 | 
			
		||||
<files psalm-version="5.4.0@62db5d4f6a7ae0a20f7cc5a4952d730272fc0863">
 | 
			
		||||
  <file src="lib/Model/ActivityPub/ACore.php">
 | 
			
		||||
    <InvalidArgument occurrences="1">
 | 
			
		||||
      <code>['a', 'p', 'span', 'br']</code>
 | 
			
		||||
| 
						 | 
				
			
			@ -12,20 +7,15 @@
 | 
			
		|||
    <InvalidClass occurrences="1">
 | 
			
		||||
      <code>Acore</code>
 | 
			
		||||
    </InvalidClass>
 | 
			
		||||
    <InvalidNullableReturnType occurrences="4">
 | 
			
		||||
    <InvalidNullableReturnType occurrences="1">
 | 
			
		||||
      <code>ACore</code>
 | 
			
		||||
      <code>ACore</code>
 | 
			
		||||
      <code>Document</code>
 | 
			
		||||
      <code>LinkedDataSignature</code>
 | 
			
		||||
    </InvalidNullableReturnType>
 | 
			
		||||
    <InvalidPropertyAssignmentValue occurrences="1">
 | 
			
		||||
      <code>$parent</code>
 | 
			
		||||
    </InvalidPropertyAssignmentValue>
 | 
			
		||||
    <NullableReturnStatement occurrences="4">
 | 
			
		||||
      <code>$this->icon</code>
 | 
			
		||||
      <code>$this->object</code>
 | 
			
		||||
    <NullableReturnStatement occurrences="1">
 | 
			
		||||
      <code>$this->parent</code>
 | 
			
		||||
      <code>$this->signature</code>
 | 
			
		||||
    </NullableReturnStatement>
 | 
			
		||||
    <TypeDoesNotContainNull occurrences="1">
 | 
			
		||||
      <code>$v === null</code>
 | 
			
		||||
| 
						 | 
				
			
			@ -40,28 +30,13 @@
 | 
			
		|||
      <code>$object = $cache->getItem($this->getObjectId())</code>
 | 
			
		||||
    </RedundantCondition>
 | 
			
		||||
  </file>
 | 
			
		||||
  <file src="lib/Model/Instance.php">
 | 
			
		||||
    <InvalidNullableReturnType occurrences="1">
 | 
			
		||||
      <code>Person</code>
 | 
			
		||||
    </InvalidNullableReturnType>
 | 
			
		||||
    <NullableReturnStatement occurrences="1">
 | 
			
		||||
      <code>$this->contactAccount</code>
 | 
			
		||||
    </NullableReturnStatement>
 | 
			
		||||
  </file>
 | 
			
		||||
  <file src="lib/Model/RequestQueue.php">
 | 
			
		||||
    <InvalidNullableReturnType occurrences="1">
 | 
			
		||||
      <code>InstancePath</code>
 | 
			
		||||
    </InvalidNullableReturnType>
 | 
			
		||||
    <NullableReturnStatement occurrences="1">
 | 
			
		||||
      <code>$this->instance</code>
 | 
			
		||||
    </NullableReturnStatement>
 | 
			
		||||
  </file>
 | 
			
		||||
  <file src="lib/Db/CoreRequestBuilder.php">
 | 
			
		||||
    <UndefinedMethod occurrences="3">
 | 
			
		||||
      <code>dropTable</code>
 | 
			
		||||
      <code>hasTable</code>
 | 
			
		||||
      <code>hasTable</code>
 | 
			
		||||
    </UndefinedMethod>
 | 
			
		||||
    <InvalidArgument occurrences="2"/>
 | 
			
		||||
  </file>
 | 
			
		||||
  <file src="lib/Service/CheckService.php">
 | 
			
		||||
    <RedundantCast occurrences="1">
 | 
			
		||||
| 
						 | 
				
			
			@ -81,36 +56,16 @@
 | 
			
		|||
    <TypeDoesNotContainType occurrences="1">
 | 
			
		||||
      <code>$this->maxDownloadSizeReached === true</code>
 | 
			
		||||
    </TypeDoesNotContainType>
 | 
			
		||||
  </file>
 | 
			
		||||
  <file src="lib/Service/FollowService.php">
 | 
			
		||||
    <InvalidReturnStatement occurrences="2">
 | 
			
		||||
      <code>$this->followsRequest->getFollowersByActorId($actor->getId())</code>
 | 
			
		||||
      <code>$this->followsRequest->getFollowingByActorId($actor->getId())</code>
 | 
			
		||||
    </InvalidReturnStatement>
 | 
			
		||||
    <InvalidReturnType occurrences="2">
 | 
			
		||||
      <code>Person[]</code>
 | 
			
		||||
      <code>Person[]</code>
 | 
			
		||||
    </InvalidReturnType>
 | 
			
		||||
  </file>
 | 
			
		||||
  <file src="lib/Service/HashtagService.php">
 | 
			
		||||
    <InvalidReturnStatement occurrences="1">
 | 
			
		||||
      <code>$result</code>
 | 
			
		||||
    </InvalidReturnStatement>
 | 
			
		||||
    <InvalidReturnType occurrences="1">
 | 
			
		||||
      <code>Stream[]</code>
 | 
			
		||||
    </InvalidReturnType>
 | 
			
		||||
    <InvalidArgument occurrences="8"/>
 | 
			
		||||
  </file>
 | 
			
		||||
  <file src="lib/Service/PostService.php">
 | 
			
		||||
    <InvalidNullableReturnType occurrences="1">
 | 
			
		||||
      <code>ACore</code>
 | 
			
		||||
    </InvalidNullableReturnType>
 | 
			
		||||
    <NullableReturnStatement occurrences="1">
 | 
			
		||||
      <code>$activity</code>
 | 
			
		||||
    </NullableReturnStatement>
 | 
			
		||||
    <UndefinedMethod occurrences="2">
 | 
			
		||||
      <code>setAttributedTo</code>
 | 
			
		||||
      <code>setContent</code>
 | 
			
		||||
    </UndefinedMethod>
 | 
			
		||||
    <TypeDoesNotContainType occurrences="1">
 | 
			
		||||
      <code>is_array($_FILES['attachments']['error'])</code>
 | 
			
		||||
    </TypeDoesNotContainType>
 | 
			
		||||
  </file>
 | 
			
		||||
  <file src="lib/Service/SearchService.php">
 | 
			
		||||
    <InvalidOperand occurrences="3">
 | 
			
		||||
| 
						 | 
				
			
			@ -131,9 +86,4 @@
 | 
			
		|||
      <code>$username === null</code>
 | 
			
		||||
    </TypeDoesNotContainNull>
 | 
			
		||||
  </file>
 | 
			
		||||
  <file src="lib/Tools/Traits/TNCLogger.php">
 | 
			
		||||
    <UndefinedClass occurrences="1">
 | 
			
		||||
      <code>HintException</code>
 | 
			
		||||
    </UndefinedClass>
 | 
			
		||||
  </file>
 | 
			
		||||
</files>
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Ładowanie…
	
		Reference in New Issue