mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-16 13:46:54 +00:00
library.assign_reference - support batching #4474
This commit is contained in:
@@ -74,7 +74,7 @@ def assign_brick_reference(ifc, brick, element=None, library=None, brick_uri=Non
|
|||||||
if not reference:
|
if not reference:
|
||||||
reference = ifc.run("library.add_reference", library=library)
|
reference = ifc.run("library.add_reference", library=library)
|
||||||
ifc.run("library.edit_reference", reference=reference, attributes=brick.export_brick_attributes(brick_uri))
|
ifc.run("library.edit_reference", reference=reference, attributes=brick.export_brick_attributes(brick_uri))
|
||||||
ifc.run("library.assign_reference", product=element, reference=reference)
|
ifc.run("library.assign_reference", products=[element], reference=reference)
|
||||||
project = brick.get_brickifc_project()
|
project = brick.get_brickifc_project()
|
||||||
if not project:
|
if not project:
|
||||||
project = brick.add_brickifc_project(brick.get_namespace(brick_uri))
|
project = brick.add_brickifc_project(brick.get_namespace(brick_uri))
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ def edit_library_reference(ifc, library):
|
|||||||
|
|
||||||
|
|
||||||
def assign_library_reference(ifc, obj=None, reference=None):
|
def assign_library_reference(ifc, obj=None, reference=None):
|
||||||
ifc.run("library.assign_reference", product=ifc.get_entity(obj), reference=reference)
|
ifc.run("library.assign_reference", products=[ifc.get_entity(obj)], reference=reference)
|
||||||
|
|
||||||
|
|
||||||
def unassign_library_reference(ifc, obj=None, reference=None):
|
def unassign_library_reference(ifc, obj=None, reference=None):
|
||||||
|
|||||||
@@ -124,21 +124,21 @@ class TestAssignBrickReference:
|
|||||||
ifc.run("library.add_reference", library="library").should_be_called().will_return("reference")
|
ifc.run("library.add_reference", library="library").should_be_called().will_return("reference")
|
||||||
brick.export_brick_attributes("brick_uri").should_be_called().will_return("attributes")
|
brick.export_brick_attributes("brick_uri").should_be_called().will_return("attributes")
|
||||||
ifc.run("library.edit_reference", reference="reference", attributes="attributes").should_be_called()
|
ifc.run("library.edit_reference", reference="reference", attributes="attributes").should_be_called()
|
||||||
ifc.run("library.assign_reference", product="element", reference="reference").should_be_called()
|
ifc.run("library.assign_reference", products=["element"], reference="reference").should_be_called()
|
||||||
brick.get_brickifc_project().should_be_called().will_return("project")
|
brick.get_brickifc_project().should_be_called().will_return("project")
|
||||||
brick.add_brickifc_reference("brick_uri", "element", "project").should_be_called()
|
brick.add_brickifc_reference("brick_uri", "element", "project").should_be_called()
|
||||||
subject.assign_brick_reference(ifc, brick, element="element", library="library", brick_uri="brick_uri")
|
subject.assign_brick_reference(ifc, brick, element="element", library="library", brick_uri="brick_uri")
|
||||||
|
|
||||||
def test_assigning_to_an_existing_reference(self, ifc, brick):
|
def test_assigning_to_an_existing_reference(self, ifc, brick):
|
||||||
brick.get_library_brick_reference("library", "brick_uri").should_be_called().will_return("reference")
|
brick.get_library_brick_reference("library", "brick_uri").should_be_called().will_return("reference")
|
||||||
ifc.run("library.assign_reference", product="element", reference="reference").should_be_called()
|
ifc.run("library.assign_reference", products=["element"], reference="reference").should_be_called()
|
||||||
brick.get_brickifc_project().should_be_called().will_return("project")
|
brick.get_brickifc_project().should_be_called().will_return("project")
|
||||||
brick.add_brickifc_reference("brick_uri", "element", "project").should_be_called()
|
brick.add_brickifc_reference("brick_uri", "element", "project").should_be_called()
|
||||||
subject.assign_brick_reference(ifc, brick, element="element", library="library", brick_uri="brick_uri")
|
subject.assign_brick_reference(ifc, brick, element="element", library="library", brick_uri="brick_uri")
|
||||||
|
|
||||||
def test_adding_a_brickifc_project_if_it_doesnt_exist(self, ifc, brick):
|
def test_adding_a_brickifc_project_if_it_doesnt_exist(self, ifc, brick):
|
||||||
brick.get_library_brick_reference("library", "brick_uri").should_be_called().will_return("reference")
|
brick.get_library_brick_reference("library", "brick_uri").should_be_called().will_return("reference")
|
||||||
ifc.run("library.assign_reference", product="element", reference="reference").should_be_called()
|
ifc.run("library.assign_reference", products=["element"], reference="reference").should_be_called()
|
||||||
brick.get_brickifc_project().should_be_called().will_return(None)
|
brick.get_brickifc_project().should_be_called().will_return(None)
|
||||||
brick.get_namespace("brick_uri").should_be_called().will_return("namespace")
|
brick.get_namespace("brick_uri").should_be_called().will_return("namespace")
|
||||||
brick.add_brickifc_project("namespace").should_be_called().will_return("project")
|
brick.add_brickifc_project("namespace").should_be_called().will_return("project")
|
||||||
@@ -277,4 +277,4 @@ class TestSetBrickListRoot:
|
|||||||
class TestRemoveBrickRelation:
|
class TestRemoveBrickRelation:
|
||||||
def test_run(self, brick):
|
def test_run(self, brick):
|
||||||
brick.remove_relation("brick_uri", "predicate", "object").should_be_called()
|
brick.remove_relation("brick_uri", "predicate", "object").should_be_called()
|
||||||
subject.remove_brick_relation(brick, brick_uri="brick_uri", predicate="predicate", object="object")
|
subject.remove_brick_relation(brick, brick_uri="brick_uri", predicate="predicate", object="object")
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ class TestEditLibraryReference:
|
|||||||
class TestAssignLibraryReference:
|
class TestAssignLibraryReference:
|
||||||
def test_run(self, ifc):
|
def test_run(self, ifc):
|
||||||
ifc.get_entity("obj").should_be_called().will_return("product")
|
ifc.get_entity("obj").should_be_called().will_return("product")
|
||||||
ifc.run("library.assign_reference", product="product", reference="reference").should_be_called()
|
ifc.run("library.assign_reference", products=["product"], reference="reference").should_be_called()
|
||||||
subject.assign_library_reference(ifc, obj="obj", reference="reference")
|
subject.assign_library_reference(ifc, obj="obj", reference="reference")
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -93,6 +93,9 @@ ARGUMENTS_DEPRECATION = {
|
|||||||
"classification.remove_reference": partial(
|
"classification.remove_reference": partial(
|
||||||
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||||
),
|
),
|
||||||
|
"library.assign_reference": partial(
|
||||||
|
batching_argument_deprecation, prev_argument="product", new_argument="products"
|
||||||
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,23 +17,30 @@
|
|||||||
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
# along with IfcOpenShell. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
import ifcopenshell
|
import ifcopenshell
|
||||||
|
import ifcopenshell.api
|
||||||
|
import ifcopenshell.util.element
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
|
||||||
class Usecase:
|
class Usecase:
|
||||||
def __init__(self, file, product=None, reference=None):
|
def __init__(
|
||||||
"""Associates a product with a library reference
|
self, file: ifcopenshell.file, products: ifcopenshell.entity_instance, reference: ifcopenshell.entity_instance
|
||||||
|
):
|
||||||
|
"""Associates a list products with a library reference
|
||||||
|
|
||||||
A product may be associated with zero, one, or many references across
|
A product may be associated with zero, one, or many references across
|
||||||
multiple libraries. See ifcopenshell.api.library.add_reference for more
|
multiple libraries. See ifcopenshell.api.library.add_reference for more
|
||||||
detail about how references work.
|
detail about how references work.
|
||||||
|
|
||||||
:param product: The IfcProduct you want to associate with the reference
|
:param products: The list of IfcProducts you want to associate with the reference
|
||||||
:type product: ifcopenshell.entity_instance.entity_instance
|
:type products: list[ifcopenshell.entity_instance.entity_instance]
|
||||||
:param reference: The IfcLibraryReference you want the product to be
|
:param reference: The IfcLibraryReference you want the product to be
|
||||||
associated with.
|
associated with.
|
||||||
:type reference: ifcopenshell.entity_instance.entity_instance
|
:type reference: ifcopenshell.entity_instance.entity_instance
|
||||||
:return: The IfcRelAssociatesLibrary relationship entity
|
:return: The IfcRelAssociatesLibrary relationship entity
|
||||||
:rtype: ifcopenshell.entity_instance.entity_instance
|
or `None` if `products` was an empty list or all products were
|
||||||
|
already assigned to the `reference`.
|
||||||
|
:rtype: Union[ifcopenshell.entity_instance.entity_instance, None]
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
|
|
||||||
@@ -51,40 +58,46 @@ class Usecase:
|
|||||||
ifc_class="IfcUnitaryEquipment", predefined_type="AIRHANDLER")
|
ifc_class="IfcUnitaryEquipment", predefined_type="AIRHANDLER")
|
||||||
|
|
||||||
# And now assign the IFC model's AHU with its Brickschema counterpart
|
# And now assign the IFC model's AHU with its Brickschema counterpart
|
||||||
ifcopenshell.api.run("library.assign_reference", model, reference=reference, product=ahu)
|
ifcopenshell.api.run("library.assign_reference", model, reference=reference, products=[ahu])
|
||||||
"""
|
"""
|
||||||
self.file = file
|
self.file = file
|
||||||
self.settings = {
|
self.settings = {
|
||||||
"product": product,
|
"products": products,
|
||||||
"reference": reference,
|
"reference": reference,
|
||||||
}
|
}
|
||||||
|
|
||||||
def execute(self):
|
def execute(self) -> Union[ifcopenshell.entity_instance, None]:
|
||||||
|
# TODO: do we need to support non-ifcroot elements like we do in classification.add_reference?
|
||||||
|
|
||||||
|
referenced_elements = ifcopenshell.util.element.get_referenced_elements(self.settings["reference"])
|
||||||
|
products: set[ifcopenshell.entity_instance] = set(self.settings["products"])
|
||||||
|
products = products - referenced_elements
|
||||||
|
|
||||||
|
if not products:
|
||||||
|
return
|
||||||
|
|
||||||
if self.file.schema == "IFC2X3":
|
if self.file.schema == "IFC2X3":
|
||||||
rels = self.get_ifc2x3_rels()
|
rel = next(
|
||||||
|
(
|
||||||
|
r
|
||||||
|
for r in self.file.by_type("IfcRelAssociatesLibrary")
|
||||||
|
if r.RelatingLibrary == self.settings["reference"]
|
||||||
|
),
|
||||||
|
None,
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
rels = self.settings["reference"].LibraryRefForObjects
|
rel = next(iter(self.settings["reference"].LibraryRefForObjects), None)
|
||||||
if not rels:
|
|
||||||
|
if not rel:
|
||||||
return self.file.create_entity(
|
return self.file.create_entity(
|
||||||
"IfcRelAssociatesLibrary",
|
"IfcRelAssociatesLibrary",
|
||||||
GlobalId=ifcopenshell.guid.new(),
|
GlobalId=ifcopenshell.guid.new(),
|
||||||
OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", self.file),
|
OwnerHistory=ifcopenshell.api.run("owner.create_owner_history", self.file),
|
||||||
RelatedObjects=[self.settings["product"]],
|
RelatedObjects=list(products),
|
||||||
RelatingLibrary=self.settings["reference"],
|
RelatingLibrary=self.settings["reference"],
|
||||||
)
|
)
|
||||||
|
|
||||||
for rel in rels:
|
related_objects = set(rel.RelatedObjects) | products
|
||||||
if self.settings["product"] in rel.RelatedObjects:
|
rel.RelatedObjects = list(related_objects)
|
||||||
return rel
|
|
||||||
|
|
||||||
rel = rels[0]
|
|
||||||
related_objects = list(rel.RelatedObjects)
|
|
||||||
related_objects.append(self.settings["product"])
|
|
||||||
rel.RelatedObjects = related_objects
|
|
||||||
ifcopenshell.api.run("owner.update_owner_history", self.file, element=rel)
|
ifcopenshell.api.run("owner.update_owner_history", self.file, element=rel)
|
||||||
return rel
|
return rel
|
||||||
|
|
||||||
def get_ifc2x3_rels(self):
|
|
||||||
return [
|
|
||||||
r for r in self.file.by_type("IfcRelAssociatesLibrary") if r.RelatingLibrary == self.settings["reference"]
|
|
||||||
]
|
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ class Usecase:
|
|||||||
ifc_class="IfcUnitaryEquipment", predefined_type="AIRHANDLER")
|
ifc_class="IfcUnitaryEquipment", predefined_type="AIRHANDLER")
|
||||||
|
|
||||||
# And now assign the IFC model's AHU with its Brickschema counterpart
|
# And now assign the IFC model's AHU with its Brickschema counterpart
|
||||||
ifcopenshell.api.run("library.assign_reference", model, reference=reference, product=ahu)
|
ifcopenshell.api.run("library.assign_reference", model, reference=reference, products=[ahu])
|
||||||
|
|
||||||
# Let's change our mind and unassign it.
|
# Let's change our mind and unassign it.
|
||||||
ifcopenshell.api.run("library.unassign_reference", model, reference=reference, product=ahu)
|
ifcopenshell.api.run("library.unassign_reference", model, reference=reference, product=ahu)
|
||||||
|
|||||||
@@ -20,39 +20,48 @@ import test.bootstrap
|
|||||||
import ifcopenshell.api
|
import ifcopenshell.api
|
||||||
|
|
||||||
|
|
||||||
|
def validate_ifc_file(ifc_file: ifcopenshell.file, use_json=True):
|
||||||
|
import ifcopenshell
|
||||||
|
import ifcopenshell.validate
|
||||||
|
|
||||||
|
if use_json:
|
||||||
|
logger = ifcopenshell.validate.json_logger()
|
||||||
|
else:
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger("validate")
|
||||||
|
logger.setLevel(logging.DEBUG)
|
||||||
|
|
||||||
|
ifcopenshell.validate.validate(ifc_file, logger, express_rules=True)
|
||||||
|
if use_json:
|
||||||
|
if logger.statements:
|
||||||
|
from pprint import pprint
|
||||||
|
|
||||||
|
pprint(logger.statements)
|
||||||
|
else:
|
||||||
|
print("IFC is completely valid.")
|
||||||
|
|
||||||
|
|
||||||
class TestAssignReference(test.bootstrap.IFC4):
|
class TestAssignReference(test.bootstrap.IFC4):
|
||||||
def test_assigning_a_reference(self):
|
def test_assigning_a_reference(self):
|
||||||
reference = self.file.createIfcLibraryReference()
|
reference = self.file.createIfcLibraryReference()
|
||||||
product = self.file.createIfcWall()
|
product = self.file.createIfcWall()
|
||||||
product2 = self.file.createIfcWall()
|
product2 = self.file.createIfcWall()
|
||||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
product3 = self.file.createIfcWall()
|
||||||
assert reference.LibraryRefForObjects[0].RelatedObjects == (product,)
|
ifcopenshell.api.run("library.assign_reference", self.file, products=[product], reference=reference)
|
||||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product2, reference=reference)
|
rel = self.file.by_type("IfcRelAssociatesLibrary")[0]
|
||||||
assert reference.LibraryRefForObjects[0].RelatedObjects == (product, product2)
|
assert rel.RelatedObjects == (product,)
|
||||||
|
ifcopenshell.api.run("library.assign_reference", self.file, products=[product2, product3], reference=reference)
|
||||||
|
assert set(rel.RelatedObjects) == set((product, product2, product3))
|
||||||
|
|
||||||
def test_not_assigning_twice(self):
|
def test_not_assigning_twice(self):
|
||||||
reference = self.file.createIfcLibraryReference()
|
reference = self.file.createIfcLibraryReference()
|
||||||
product = self.file.createIfcWall()
|
product = self.file.createIfcWall()
|
||||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
ifcopenshell.api.run("library.assign_reference", self.file, products=[product], reference=reference)
|
||||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
ifcopenshell.api.run("library.assign_reference", self.file, products=[product], reference=reference)
|
||||||
assert reference.LibraryRefForObjects[0].RelatedObjects == (product,)
|
|
||||||
|
|
||||||
|
|
||||||
class TestAssignReferenceIFC2X3(test.bootstrap.IFC2X3):
|
|
||||||
def test_assigning_a_reference(self):
|
|
||||||
reference = self.file.createIfcLibraryReference()
|
|
||||||
product = self.file.createIfcWall()
|
|
||||||
product2 = self.file.createIfcWall()
|
|
||||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
|
||||||
rel = self.file.by_type("IfcRelAssociatesLibrary")[0]
|
rel = self.file.by_type("IfcRelAssociatesLibrary")[0]
|
||||||
assert rel.RelatedObjects == (product,)
|
assert rel.RelatedObjects == (product,)
|
||||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product2, reference=reference)
|
|
||||||
assert rel.RelatedObjects == (product, product2)
|
|
||||||
|
|
||||||
def test_not_assigning_twice(self):
|
|
||||||
reference = self.file.createIfcLibraryReference()
|
class TestAssignReferenceIFC2X3(test.bootstrap.IFC2X3, TestAssignReference):
|
||||||
product = self.file.createIfcWall()
|
pass
|
||||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
|
||||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
|
||||||
rel = self.file.by_type("IfcRelAssociatesLibrary")[0]
|
|
||||||
assert rel.RelatedObjects == (product,)
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ class TestRemoveReference(test.bootstrap.IFC4):
|
|||||||
def test_removing_a_reference(self):
|
def test_removing_a_reference(self):
|
||||||
reference = self.file.createIfcLibraryReference()
|
reference = self.file.createIfcLibraryReference()
|
||||||
product = self.file.createIfcWall()
|
product = self.file.createIfcWall()
|
||||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
ifcopenshell.api.run("library.assign_reference", self.file, products=[product], reference=reference)
|
||||||
ifcopenshell.api.run("library.remove_reference", self.file, reference=reference)
|
ifcopenshell.api.run("library.remove_reference", self.file, reference=reference)
|
||||||
assert len(self.file.by_type("IfcLibraryReference")) == 0
|
assert len(self.file.by_type("IfcLibraryReference")) == 0
|
||||||
assert len(self.file.by_type("IfcRelAssociatesLibrary")) == 0
|
assert len(self.file.by_type("IfcRelAssociatesLibrary")) == 0
|
||||||
|
|||||||
@@ -24,6 +24,6 @@ class TestUnassignReference(test.bootstrap.IFC4):
|
|||||||
def test_unassigning_a_reference(self):
|
def test_unassigning_a_reference(self):
|
||||||
reference = self.file.createIfcLibraryReference()
|
reference = self.file.createIfcLibraryReference()
|
||||||
product = self.file.createIfcWall()
|
product = self.file.createIfcWall()
|
||||||
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
ifcopenshell.api.run("library.assign_reference", self.file, products=[product], reference=reference)
|
||||||
ifcopenshell.api.run("library.unassign_reference", self.file, product=product, reference=reference)
|
ifcopenshell.api.run("library.unassign_reference", self.file, product=product, reference=reference)
|
||||||
assert len(self.file.by_type("IfcRelAssociatesLibrary")) == 0
|
assert len(self.file.by_type("IfcRelAssociatesLibrary")) == 0
|
||||||
|
|||||||
@@ -236,3 +236,13 @@ class TestTemporarySupportForDeprecatedAPIArguments(test.bootstrap.IFC4):
|
|||||||
ifcopenshell.api.run("classification.remove_reference", self.file, product=element, reference=reference)
|
ifcopenshell.api.run("classification.remove_reference", self.file, product=element, reference=reference)
|
||||||
assert len(ifcopenshell.util.classification.get_references(element)) == 0
|
assert len(ifcopenshell.util.classification.get_references(element)) == 0
|
||||||
assert len(self.file.by_type("IfcClassificationReference")) == 0
|
assert len(self.file.by_type("IfcClassificationReference")) == 0
|
||||||
|
|
||||||
|
@deprecation_check
|
||||||
|
def test_assigning_a_reference(self):
|
||||||
|
reference = self.file.createIfcLibraryReference()
|
||||||
|
product = self.file.createIfcWall()
|
||||||
|
product2 = self.file.createIfcWall()
|
||||||
|
ifcopenshell.api.run("library.assign_reference", self.file, product=product, reference=reference)
|
||||||
|
assert reference.LibraryRefForObjects[0].RelatedObjects == (product,)
|
||||||
|
ifcopenshell.api.run("library.assign_reference", self.file, product=product2, reference=reference)
|
||||||
|
assert set(reference.LibraryRefForObjects[0].RelatedObjects) == set((product, product2))
|
||||||
|
|||||||
@@ -788,7 +788,6 @@ class TestGetNestIFC2X3(test.bootstrap.IFC2X3, TestGetNestIFC4):
|
|||||||
class TestGetReferencedElements(test.bootstrap.IFC4):
|
class TestGetReferencedElements(test.bootstrap.IFC4):
|
||||||
# TODO: test other references:
|
# TODO: test other references:
|
||||||
# IfcDocumentReference
|
# IfcDocumentReference
|
||||||
# IfcLibraryReference
|
|
||||||
# IfcExternallyDefinedHatchStyle
|
# IfcExternallyDefinedHatchStyle
|
||||||
# IfcExternallyDefinedSurfaceStyle
|
# IfcExternallyDefinedSurfaceStyle
|
||||||
# IfcExternallyDefinedTextFont
|
# IfcExternallyDefinedTextFont
|
||||||
@@ -808,6 +807,15 @@ class TestGetReferencedElements(test.bootstrap.IFC4):
|
|||||||
)
|
)
|
||||||
assert subject.get_referenced_elements(reference) == set(elements)
|
assert subject.get_referenced_elements(reference) == set(elements)
|
||||||
|
|
||||||
|
def test_get_elements_referenced_by_library_reference(self):
|
||||||
|
reference = self.file.createIfcLibraryReference()
|
||||||
|
elements = [
|
||||||
|
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall"),
|
||||||
|
ifcopenshell.api.run("root.create_entity", self.file, ifc_class="IfcWall"),
|
||||||
|
]
|
||||||
|
ifcopenshell.api.run("library.assign_reference", self.file, reference=reference, products=elements)
|
||||||
|
assert subject.get_referenced_elements(reference) == set(elements)
|
||||||
|
|
||||||
|
|
||||||
class TestGetReferencedElementsIFC2X3(test.bootstrap.IFC2X3, TestGetReferencedElements):
|
class TestGetReferencedElementsIFC2X3(test.bootstrap.IFC2X3, TestGetReferencedElements):
|
||||||
pass
|
pass
|
||||||
|
|||||||
Reference in New Issue
Block a user