# Redmine - project management software # Copyright (C) 2006-2014 Jean-Philippe Lang # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public License # as published by the Free Software Foundation; either version 2 # 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 General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. require File.expand_path('../../test_helper', __FILE__) class RepositoryTest < ActiveSupport::TestCase fixtures :projects, :trackers, :projects_trackers, :enabled_modules, :repositories, :issues, :issue_statuses, :issue_categories, :changesets, :changes, :users, :members, :member_roles, :roles, :enumerations include Redmine::I18n def setup @repository = Project.find(1).repository end def test_blank_log_encoding_error_message set_language_if_valid 'en' repo = Repository::Bazaar.new( :project => Project.find(3), :url => "/test", :log_encoding => '' ) assert !repo.save assert_include "Commit messages encoding can't be blank", repo.errors.full_messages end def test_blank_log_encoding_error_message_fr set_language_if_valid 'fr' str = "Encodage des messages de commit doit \xc3\xaatre renseign\xc3\xa9(e)" str.force_encoding('UTF-8') if str.respond_to?(:force_encoding) repo = Repository::Bazaar.new( :project => Project.find(3), :url => "/test" ) assert !repo.save assert_include str, repo.errors.full_messages end def test_create repository = Repository::Subversion.new(:project => Project.find(3)) assert !repository.save repository.url = "svn://localhost" assert repository.save repository.reload project = Project.find(3) assert_equal repository, project.repository end def test_first_repository_should_be_set_as_default repository1 = Repository::Subversion.new( :project => Project.find(3), :identifier => 'svn1', :url => 'file:///svn1' ) assert repository1.save assert repository1.is_default? repository2 = Repository::Subversion.new( :project => Project.find(3), :identifier => 'svn2', :url => 'file:///svn2' ) assert repository2.save assert !repository2.is_default? assert_equal repository1, Project.find(3).repository assert_equal [repository1, repository2], Project.find(3).repositories.sort end def test_identifier_should_accept_letters_digits_dashes_and_underscores r = Repository::Subversion.new( :project_id => 3, :identifier => 'svn-123_45', :url => 'file:///svn' ) assert r.save end def test_identifier_should_not_be_frozen_for_a_new_repository assert_equal false, Repository.new.identifier_frozen? end def test_identifier_should_not_be_frozen_for_a_saved_repository_with_blank_identifier Repository.update_all(["identifier = ''"], "id = 10") assert_equal false, Repository.find(10).identifier_frozen? end def test_identifier_should_be_frozen_for_a_saved_repository_with_valid_identifier Repository.update_all(["identifier = 'abc123'"], "id = 10") assert_equal true, Repository.find(10).identifier_frozen? end def test_identifier_should_not_accept_change_if_frozen r = Repository.new(:identifier => 'foo') r.stubs(:identifier_frozen?).returns(true) r.identifier = 'bar' assert_equal 'foo', r.identifier end def test_identifier_should_accept_change_if_not_frozen r = Repository.new(:identifier => 'foo') r.stubs(:identifier_frozen?).returns(false) r.identifier = 'bar' assert_equal 'bar', r.identifier end def test_destroy repository = Repository.find(10) changesets = repository.changesets.count changes = repository.filechanges.count assert_difference 'Changeset.count', -changesets do assert_difference 'Change.count', -changes do Repository.find(10).destroy end end end def test_destroy_should_delete_parents_associations changeset = Changeset.find(102) changeset.parents = Changeset.find_all_by_id([100, 101]) assert_difference 'Changeset.connection.select_all("select * from changeset_parents").size', -2 do Repository.find(10).destroy end end def test_destroy_should_delete_issues_associations changeset = Changeset.find(102) changeset.issues = Issue.find_all_by_id([1, 2]) assert_difference 'Changeset.connection.select_all("select * from changesets_issues").size', -2 do Repository.find(10).destroy end end def test_should_not_create_with_disabled_scm # disable Subversion with_settings :enabled_scm => ['Darcs', 'Git'] do repository = Repository::Subversion.new( :project => Project.find(3), :url => "svn://localhost") assert !repository.save assert_include I18n.translate('activerecord.errors.messages.invalid'), repository.errors[:type] end end def test_scan_changesets_for_issue_ids Setting.default_language = 'en' Setting.commit_ref_keywords = 'refs , references, IssueID' Setting.commit_update_keywords = [ {'keywords' => 'fixes , closes', 'status_id' => IssueStatus.where(:is_closed => true).first.id, 'done_ratio' => '90'} ] Setting.default_language = 'en' ActionMailer::Base.deliveries.clear # make sure issue 1 is not already closed fixed_issue = Issue.find(1) assert !fixed_issue.status.is_closed? old_status = fixed_issue.status with_settings :notified_events => %w(issue_added issue_updated) do Repository.scan_changesets_for_issue_ids end assert_equal [101, 102], Issue.find(3).changeset_ids # fixed issues fixed_issue.reload assert fixed_issue.status.is_closed? assert_equal 90, fixed_issue.done_ratio assert_equal [101], fixed_issue.changeset_ids # issue change journal = fixed_issue.journals.reorder('created_on desc').first assert_equal User.find_by_login('dlopper'), journal.user assert_equal 'Applied in changeset r2.', journal.notes # 2 email notifications assert_equal 2, ActionMailer::Base.deliveries.size mail = ActionMailer::Base.deliveries.first assert_not_nil mail assert mail.subject.starts_with?( "[#{fixed_issue.project.name} - #{fixed_issue.tracker.name} ##{fixed_issue.id}]") assert_mail_body_match( "Status changed from #{old_status} to #{fixed_issue.status}", mail) # ignoring commits referencing an issue of another project assert_equal [], Issue.find(4).changesets end def test_for_changeset_comments_strip repository = Repository::Mercurial.create( :project => Project.find( 4 ), :url => '/foo/bar/baz' ) comment = <<-COMMENT This is a loooooooooooooooooooooooooooong comment COMMENT changeset = Changeset.new( :comments => comment, :commit_date => Time.now, :revision => 0, :scmid => 'f39b7922fb3c', :committer => 'foo ', :committed_on => Time.now, :repository => repository ) assert( changeset.save ) assert_not_equal( comment, changeset.comments ) assert_equal( 'This is a loooooooooooooooooooooooooooong comment', changeset.comments ) end def test_for_urls_strip_cvs repository = Repository::Cvs.create( :project => Project.find(4), :url => ' :pserver:login:password@host:/path/to/the/repository', :root_url => 'foo ', :log_encoding => 'UTF-8') assert repository.save repository.reload assert_equal ':pserver:login:password@host:/path/to/the/repository', repository.url assert_equal 'foo', repository.root_url end def test_for_urls_strip_subversion repository = Repository::Subversion.create( :project => Project.find(4), :url => ' file:///dummy ') assert repository.save repository.reload assert_equal 'file:///dummy', repository.url end def test_for_urls_strip_git repository = Repository::Git.create( :project => Project.find(4), :url => ' c:\dummy ') assert repository.save repository.reload assert_equal 'c:\dummy', repository.url end def test_manual_user_mapping assert_no_difference "Changeset.where('user_id <> 2').count" do c = Changeset.create!( :repository => @repository, :committer => 'foo', :committed_on => Time.now, :revision => 100, :comments => 'Committed by foo.' ) assert_nil c.user @repository.committer_ids = {'foo' => '2'} assert_equal User.find(2), c.reload.user # committer is now mapped c = Changeset.create!( :repository => @repository, :committer => 'foo', :committed_on => Time.now, :revision => 101, :comments => 'Another commit by foo.' ) assert_equal User.find(2), c.user end end def test_auto_user_mapping_by_username c = Changeset.create!( :repository => @repository, :committer => 'jsmith', :committed_on => Time.now, :revision => 100, :comments => 'Committed by john.' ) assert_equal User.find(2), c.user end def test_auto_user_mapping_by_email c = Changeset.create!( :repository => @repository, :committer => 'john ', :committed_on => Time.now, :revision => 100, :comments => 'Committed by john.' ) assert_equal User.find(2), c.user end def test_filesystem_avaialbe klass = Repository::Filesystem assert klass.scm_adapter_class assert_equal true, klass.scm_available end def test_extra_info_should_not_return_non_hash_value repo = Repository.new repo.extra_info = "foo" assert_nil repo.extra_info end def test_merge_extra_info repo = Repository::Subversion.new(:project => Project.find(3)) assert !repo.save repo.url = "svn://localhost" assert repo.save repo.reload project = Project.find(3) assert_equal repo, project.repository assert_nil repo.extra_info h1 = {"test_1" => {"test_11" => "test_value_11"}} repo.merge_extra_info(h1) assert_equal h1, repo.extra_info h2 = {"test_2" => { "test_21" => "test_value_21", "test_22" => "test_value_22", }} repo.merge_extra_info(h2) assert_equal (h = {"test_11" => "test_value_11"}), repo.extra_info["test_1"] assert_equal "test_value_21", repo.extra_info["test_2"]["test_21"] h3 = {"test_2" => { "test_23" => "test_value_23", "test_24" => "test_value_24", }} repo.merge_extra_info(h3) assert_equal (h = {"test_11" => "test_value_11"}), repo.extra_info["test_1"] assert_nil repo.extra_info["test_2"]["test_21"] assert_equal "test_value_23", repo.extra_info["test_2"]["test_23"] end def test_sort_should_not_raise_an_error_with_nil_identifiers r1 = Repository.new r2 = Repository.new assert_nothing_raised do [r1, r2].sort end end end able23-update-code-signing-crl'>automated/noid/stable23-update-code-signing-crl Nextcloud server, a safe home for all your data: https://github.com/nextcloud/serverwww-data
aboutsummaryrefslogtreecommitdiffstats
blob: 4b1a6d32e8e76ec0023284ffe7dce5ec4a1bb5d9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
<?php

declare(strict_types=1);
/**
 * SPDX-FileCopyrightText: 2023 Nextcloud GmbH and Nextcloud contributors
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

namespace OCP\FilesMetadata;

use OCP\DB\QueryBuilder\IQueryBuilder;
use OCP\Files\Node;
use OCP\FilesMetadata\Exceptions\FilesMetadataException;
use OCP\FilesMetadata\Exceptions\FilesMetadataNotFoundException;
use OCP\FilesMetadata\Model\IFilesMetadata;
use OCP\FilesMetadata\Model\IMetadataValueWrapper;

/**
 * Manager for FilesMetadata; manage files' metadata.
 *
 * @since 28.0.0
 */
interface IFilesMetadataManager {
	/** @since 28.0.0 */
	public const PROCESS_LIVE = 1;
	/** @since 28.0.0 */
	public const PROCESS_BACKGROUND = 2;
	/** @since 28.0.0 */
	public const PROCESS_NAMED = 4;

	/**
	 * initiate the process of refreshing the metadata in relation to a node
	 * usually, this process:
	 * - get current metadata from database, if available, or create a new one
	 * - dispatch a MetadataLiveEvent,
	 * - save new metadata in database, if metadata have been changed during the event
	 * - refresh metadata indexes if needed,
	 * - prep a new cronjob if an app request it during the event,
	 *
	 * @param Node $node related node
	 * @param int $process type of process
	 * @param string $namedEvent limit process to a named event
	 *
	 * @return IFilesMetadata
	 * @see self::PROCESS_BACKGROUND
	 * @see self::PROCESS_LIVE
	 * @see self::PROCESS_NAMED
	 * @since 28.0.0
	 */
	public function refreshMetadata(
		Node $node,
		int $process = self::PROCESS_LIVE,
		string $namedEvent = '',
	): IFilesMetadata;

	/**
	 * returns metadata of a file id
	 *
	 * @param int $fileId file id
	 * @param boolean $generate Generate if metadata does not exist
	 *
	 * @return IFilesMetadata
	 * @throws FilesMetadataNotFoundException if not found
	 * @since 28.0.0
	 */
	public function getMetadata(int $fileId, bool $generate = false): IFilesMetadata;

	/**
	 * returns metadata of multiple file ids
	 *
	 * @param int[] $fileIds file ids
	 *
	 * @return array File ID is the array key, files without metadata are not returned in the array
	 * @psalm-return array<int, IFilesMetadata>
	 * @since 28.0.0
	 */
	public function getMetadataForFiles(array $fileIds): array;

	/**
	 * save metadata to database and refresh indexes.
	 * metadata are saved if new data are available.
	 * on update, a check on syncToken is done to avoid conflict (race condition)
	 *
	 * @param IFilesMetadata $filesMetadata
	 *
	 * @throws FilesMetadataException if metadata seems malformed
	 * @since 28.0.0
	 */
	public function saveMetadata(IFilesMetadata $filesMetadata): void;

	/**
	 * delete metadata and its indexes
	 *
	 * @param int $fileId file id
	 *
	 * @return void
	 * @since 28.0.0
	 */
	public function deleteMetadata(int $fileId): void;

	/**
	 * generate and return a MetadataQuery to help building sql queries
	 *
	 * @param IQueryBuilder $qb
	 * @param string $fileTableAlias alias of the table that contains data about files
	 * @param string $fileIdField alias of the field that contains file ids
	 *
	 * @return IMetadataQuery
	 * @see IMetadataQuery
	 * @since 28.0.0
	 */
	public function getMetadataQuery(
		IQueryBuilder $qb,
		string $fileTableAlias,
		string $fileIdField,
	): IMetadataQuery;

	/**
	 * returns all type of metadata currently available.
	 * The list is stored in a IFilesMetadata with null values but correct type.
	 *
	 * Note: this method loads lazy appconfig values.
	 *
	 * @return IFilesMetadata
	 * @since 28.0.0
	 */
	public function getKnownMetadata(): IFilesMetadata;

	/**
	 * Initiate a metadata key with its type.
	 *
	 * The call is mandatory before using the metadata property in a webdav request.
	 * The call should be part of a migration/repair step and not be called on app's boot
	 * process as it is using lazy-appconfig value
	 *
	 * Note: this method loads lazy appconfig values.
	 *
	 * @param string $key metadata key
	 * @param string $type metadata type
	 * @param bool $indexed TRUE if metadata can be search
	 * @param int $editPermission remote edit permission via Webdav PROPPATCH
	 *
	 * @see IMetadataValueWrapper::TYPE_INT
	 * @see IMetadataValueWrapper::TYPE_FLOAT
	 * @see IMetadataValueWrapper::TYPE_BOOL
	 * @see IMetadataValueWrapper::TYPE_ARRAY
	 * @see IMetadataValueWrapper::TYPE_STRING_LIST
	 * @see IMetadataValueWrapper::TYPE_INT_LIST
	 * @see IMetadataValueWrapper::TYPE_STRING
	 * @see IMetadataValueWrapper::EDIT_FORBIDDEN
	 * @see IMetadataValueWrapper::EDIT_REQ_OWNERSHIP
	 * @see IMetadataValueWrapper::EDIT_REQ_WRITE_PERMISSION
	 * @see IMetadataValueWrapper::EDIT_REQ_READ_PERMISSION
	 * @since 28.0.0
	 * @since 29.0.0 uses lazy config value - do not use this method out of repair steps
	 */
	public function initMetadata(string $key, string $type, bool $indexed, int $editPermission): void;
}